Blazor Page Combobox DataSource to async method - async-await

I have an issue where I need to set DataSource for a combo box to a service's Async method.
<div class="col-xs-5 col-sm-5 col-lg-5 col-md-5">
<SfComboBox TValue="string" TItem="ProjectStatusViewModel" PopupHeight="230px" Placeholder="Project Status" FloatLabelType="#FloatLabelType.Auto"
DataSource="#LookUpService.GetProjectStatuses()" #bind-Value="#_projectToEdit.Status">
<ComboBoxFieldSettings Text="Name" Value="Name"></ComboBoxFieldSettings>
</SfComboBox>
</div>
I'm getting this error:
cannot convert from 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<DesignTracker.Application.ViewModels.ProjectStatusViewModel>>'
to
'System.Collections.Generic.IEnumerable<DesignTracker.Application.ViewModels.ProjectStatusViewModel>' DesignTracker.UI.SyncfusionBlazorApp

Syncfusion support here.
We have checked the provided code example and issue details. We suspect that the reported issue may be cased due to mismatch in the type of data source and TItem in your application.
Also, we suggest you to bind the async method inside the OnInitialized method instead of assigned to the tag helper directly to avoid the issues at your end.
We have prepared the sample for your reference and attached it below.
Sample Link: https://www.syncfusion.com/downloads/support/directtrac/274346/ze/ComboBox_274346-1580423979
[index.razor]
<SfComboBox TValue="string" TItem="Countries" PopupHeight="230px" Placeholder="Project Status" FloatLabelType="Syncfusion.Blazor.Inputs.FloatLabelType.Auto"
DataSource="#DataSource" #bind-Value="#val">
<ComboBoxFieldSettings Text="Name" Value="Code"></ComboBoxFieldSettings>
</SfComboBox>
#code {
private string val { get; set; }
public CountryService DataService;
public List<Countries> DataSource = new List<Countries>();
protected override async Task OnInitializedAsync()
{
DataSource = await ownservice.GetDataAsync();
this.val = await ownservice.GetPreSelectDataAsync();
}
}
[OwnService.cs]
public class CountryService
{
public async Task<List<Countries>> GetDataAsync()
{
List<Countries> Country = new List<Countries>
{
new Countries() { Name = "Australia", Code = "AU" },
new Countries() { Name = "Bermuda", Code = "BM" },
new Countries() { Name = "Canada", Code = "CA" },
new Countries() { Name = "Cameroon", Code = "CM" },
new Countries() { Name = "Denmark", Code = "DK" },
new Countries() { Name = "France", Code = "FR" },
new Countries() { Name = "Finland", Code = "FI" }
};
return await Task.FromResult(Country);
}
public async Task<string> GetPreSelectDataAsync()
{
string value = "AU";
return await Task.FromResult(value);
}
}
[Startup.cs]
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(option => option.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSyncfusionBlazor();
services.AddSingleton<CountryService>();
}
[WeatherForecast.cs]
public class Countries
{
public string Name { get; set; }
public string Code { get; set; }
}

It looks like your DataSource is expecting an enumerable collection, whereas you are supplying it with a Task that will eventually supply that collection. Try changing it to DataSource="#(await LookUpService.GetProjectStatuses()" which might do the truck.
The second option is to set up a backing property on the Parent component that holds that collection, and make the service call programmatically to populate the list, as in within the OnInitialized method override.

Related

Google Place Api Prediction class cast to Position or something equivalent

I'm working on a Xamarin Forms project. I have a very simple page where a job seeker searches job posts by entering a location(ex. New York) and a radius(picker). I have the following code in my PageViewModel:
public class SearchPageViewModel : BaseViewModel
{
private readonly INavigation _navigation;
private readonly GooglePlacesApiService _api;
private IEnumerable<JobPost> Posts;
public int RadiusIndex {get;set;}
public SearchPageViewModel (INavigation navigation, IEnumerable<JobPost> posts)
{
_navigation = navigation;
var settings = GoogleApiSettings.Builder.WithApiKey("MY_API_KEY").Build();
_api = new GooglePlacesApiService(settings);
this.posts =posts;
}
public ICommand DoSearchCommand
=> new Command(async () => await DoSearchAsync().ConfigureAwait(false), () => CanSearch);
public ICommand SelectItemCommand
=> new Command<Prediction>(async (prediction) =>
{
//!!!Filter jobposts based on position and radius to be able to display it!!!
_api.ResetSessionToken();
});
private string _searchText;
public string SearchText
{
get => _searchText;
set
{
if (SetProperty(ref _searchText, value))
OnPropertyChanged("CanSearch");
}
}
private List<Prediction> _results;
public List<Prediction> Results
{
get => _results;
set => SetProperty(ref _results, value);
}
public bool CanSearch => !string.IsNullOrWhiteSpace(SearchText) && SearchText.Length > 2;
private async Task DoSearchAsync()
{
var results = await _api.GetPredictionsAsync(SearchText)
.ConfigureAwait(false);
if(results != null && results.Status.Equals("OK"))
{
ResultCount = results.Items.Count;
Results = results.Items;
OnPropertyChanged("HasResults");
}
}
}
public class JobPost
{
public Position Location {get;set;}
}
Ok, so far it works well. Once the search button is clicked the job seeker get a list of predictions and picks a place. But the problem is now, how do I get the positioning(longitude and latitude) of the picked prediction, so I can filter the job posts so I can dsiplay the result to the job seeker.
Thanks in advance.
use the Essentials GeoCoding plugin
var address = "New York";
var locations = await Geocoding.GetLocationsAsync(address);
locations will be a list of potential matches, each with a lat/long
var location = locations?.FirstOrDefault();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}

How to pass parameters and set properties while navigating to a new view model (initializeAsync)

I am using the design pattern mvvm, I have a view model locator and a view model base class.
The view model locator finds what view is associated to the view model. I also wrote a navigation service and one of my methods (NavigateTo) takes in a parameter (an object). the method is to navigate to a view model associated with the view.
namespace StudentData
{
public class StudentOverViewViewModel : ViewModelBase
{
private DataSet studentData;
public Icommand getDetails { get; set; }
public DataSet _data
{
get { return studentData; }
set
{
studentData = value;
RaisePropertyChanged(() => studentData);
}
}
public StudentOverViewViewModel (DataSet studentData)
{
this.studentData = studentData;
getDetails = new Command(Details);
}
public async Task getDetails()
{
// api calls done to retrieve data and set studentData to the current student data
await NavigationService.NavigateToAsync<StudentDetailViewModel>(studentData );
}
}
}
For the second view model I have :
namespace StudentData
{
public class StudentDetailViewModel: ViewModelBase
{
private DataSet Data;
public DataSet _Data
{
get
{
return Data;
}
set
{
Data= value;
RaisePropertyChanged(() => Data);
}
}
}
public StudentDetailViewModel(DataSet Data)
{
this.Data = Data;
}
public override async Task InitializeAsync(object navigationData)
{
if(navigationData is DataSet)
{
Data = (DataSet) navigationData; // after the page is initialized, the variables or properties/ models are not updated and is still null
}
}
}
My issue is that in my initializeAsync method in the second view model, I set the value and property for data, but after the method is done it set all the values back to null.
Thank you in advance for your help.
private async Task InternalNavigateToAsync(Type viewModelType, object
parameter)
{
Page page = CreatePage(viewModelType, parameter);
if (page is UserAuthenticateView)
{
Application.Current.MainPage = new CustomNiavigationView(page);
}
else
{
var navigationPage = Application.Current.MainPage as CustomNiavigationView;
if (navigationPage != null)
{
await navigationPage.PushAsync(page);
}
else
{
Application.Current.MainPage = new CustomNiavigationView(page);
}
}
await (page.BindingContext as ViewModelBase).InitializeAsync(parameter);
}

Consuming WEB API Xamarin Forms

I have a WEB API hosted on a server, there I have a Products table with Name and Description.I already checked for the postman and this is ok, when I try to implement the method in xamarin by visual studio to bring a record by its name and display in a listview I receiving the following message
Can not implicitly convert type "void"in
"System.Collections.Generic.List"
public async void GetProductByName(string Name)
{
var client = new HttpClient(handler);
client.Timeout = TimeSpan.FromSeconds(120);
txtTest.Text =
"http://www.ProdutosAPITest6.hostname.com/api/products";
var URI = txtTest.Text + "/" + Name.ToString();
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(URI)
};
var response = await client.SendAsync(requestMessage);
if (response.IsSuccessStatusCode == true)
{
var products = await response.Content.ReadAsStringAsync();
var resultModel = JsonConvert.DeserializeObject<Product>
(products);
return resultModel;
}
}
MY CLASS
namespace XF_ConsumingWebAPI.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
MY LISTVIEW
public ListView myListView { get { return ProductsList; }}
protected override async void OnAppearing()
{
var name = //pass name;
List<ProductModel> products = await GetProductByName(Name);
if (products.Count() > 0)
{
myListView.ItemsSource = products;
}
base.OnAppearing();
}
in the line List<Produto> products = await LoadData(Name);
I'm receiving the following message
Can not implicitly convert type "void" in
"System.Collections.Generic.List<XF_ConsumingWebAPI.Models.Product>"
Try to set ItemSource in GetproductByName function instead of returning resultModel i.e.
myListView.ItemSource=resultModel

Unable to bind data to Kendo Scheduler

I've got this Kendo Scheduler that is displayed in the View but without any data.
The Scheduler on the View:
#(Html.Kendo().Scheduler<ProjName.Models.ScheduleInspectionModel>()
.Name("scheduler")
.Views(views =>
{
views.DayView();
views.WorkWeekView();
views.WeekView();
views.MonthView(mv => mv.Selected(true));
views.AgendaView();
})
.Timezone("Etc/UTC")
.DataSource(d => d
.Read("ControllerName", "GetScheduleInspections")
)
)
The datasource invokes the controller method below:
public ActionResult GetScheduleInspections([DataSourceRequest]DataSourceRequest request)
{
ScheduleInspectionModel sim = new ScheduleInspectionModel();
var gsio = sim.getScheduleInspections();
List<ScheduleInspectionModel> list = new List<ScheduleInspectionModel>();
if (gsio.scheduleinspections != null)
{
foreach (wsScheduleInspection.scheduleInspectionOutput scheduleInspection in gsio.scheduleinspections)
{
ScheduleInspectionModel sim2 = new ScheduleInspectionModel
{
GlobalEquipConditionId = scheduleInspection.globalEquipmentCondition.id,
Description = scheduleInspection.globalEquipmentCondition.code,
Start = DateTime.Now,
End = DateTime.Now.AddHours(2),
Title = scheduleInspection.globalEquipmentCondition.code,
IsAllDay = true
};
list.Add(sim2);
}
}
return Json(list.ToDataSourceResult(request));
}
But this method is never run, despite being on the Scheduler Datasource property. It should run that method and return a list of inspections. I don't know why isn't the method being hit. With a Kendo Grid, for example, the method on the Datasource Read is hit as soon as the page is loaded.
Try making sure your definition has these two items as I think they are required.
.Date(new DateTime(2013, 6, 13))
.StartTime(new DateTime(2013, 6, 13, 7, 00, 00))
EDIT
I was able to get the following code to work:
Model
// NOTE: It's important that your model class implements ISchedulerEvent
public class TaskViewModel : ISchedulerEvent
{
public string Title { get; set; }
public string Description { get; set; }
public bool IsAllDay { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public string StartTimezone { get; set; }
public string EndTimezone { get; set; }
public string RecurrenceRule { get; set; }
public string RecurrenceException { get; set; }
}
SchedulerController.cs
public class SchedulerController : Controller
{
// GET: Scheduler
public ActionResult Index()
{
var model = new SchedulerViewModel();
// In this case, it doesn't matter what this model is really since we're using AJAX binding
return View(model);
}
// I usually have my binding methods for Kendo use HttpPost
[HttpPost]
public ActionResult GetData([DataSourceRequest] DataSourceRequest request)
{
var data = new List<TaskViewModel>
{
new TaskViewModel
{
Start = new DateTime(2014, 12, 1, 8, 0, 0),
End = new DateTime(2014, 12, 1, 17, 0, 0),
Title = "Task 1"
}
};
return Json(data.ToDataSourceResult(request));
}
}
Index.cshtml (view)
#(Html.Kendo().Scheduler<TaskViewModel>()
.Name("scheduler")
.Views(views =>
{
views.DayView();
views.WorkWeekView();
views.WeekView();
views.MonthView(mv => mv.Selected(true));
views.AgendaView();
})
.Timezone("Etc/UTC")
.DataSource(d => d
.Read("GetData", "Scheduler")
))
If this doesn't work for you, I would make sure your versions (for Kendo, jQuery, etc) are correct. Hope this helps.
Yes, Scheduler read is called as soon as it is loeded. But it may not be getting data in proper format as it expects. So it is not able to bind the data. If you can check for these modification:
1) Define the "Model" in "DataSource" of scheduler as defined in this example.
2) Also the action method should return object of "MyModel" class(model on which scheduler is defined)
not "ScheduleInspectionModel" class.

Validating Uploaded Files Using IValidatableObject

Hi All!
I'm a bit of a noob at model validation and i've been trying to validate an Articles object and an uploaded file using the IValidatableObject interface with no success.
This following class validates the Articles object just fine but I can't see how the HttpPostedFileBase is injected to allow me to validate against it. Is this even possible to achieve using this method?
The form i'm using to submit the data includes the enctype = multipart/form-data attribute so it knows its posting files.
This is the full class im trying to validate. This ones really got me stuck and any help will be very gratefully appreciated.
public class ArticlesModel : IValidatableObject
{
public Article Article { get; set; }
public IEnumerable<Category> Categories { get; set; }
public HttpPostedFileBase PostedFile { get; set; }
public ArticlesModel(){}
public ArticlesModel(Article article, IEnumerable<Category> categories)
{
this.Article = article;
this.Categories = categories;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Article.CategoryID == 0)
{
yield return new ValidationResult("Please select a category.", new[] { "Article.Category"});
}
if (Article.Title == null)
{
yield return new ValidationResult("Please enter a title.", new[] { "Article.Title" });
}
if (Article.Content == null)
{
yield return new ValidationResult("Please enter some content.", new[] { "Article.Content" });
}
if (PostedFile == null)
{
yield return new ValidationResult("Please upload a file.", new[] { "Article.ImageFile" });
}
else
{
if (PostedFile.ContentLength > 1 * 1024 * 1024)
{
yield return new ValidationResult("Please upload a file 1Mb or less.", new[] { "Article.ImageFile" });
}
//Other file checking logic here please!!
}
}
}

Resources