For the past few days I've been trying to get a grid working for a relatively complex model. I want to use a remote datasource for populating the initial grid, but for adding and editing I need to query other datasources for several columns, to get filtering and sorting in a dropdownlist.
I've encountered several problems, with things like binding the dropdowns and validating the editor. I'll post some of my code here, maybe someone here can provide a suggestion on what I'm doing wrong/forgetting.
Controller:
// GET: Settings public ActionResult Index() { return View(); } public async Task<ActionResult> GetSettings([DataSourceRequest] DataSourceRequest request) { DiscountSettingsViewModel viewModel = await _discountService.GetViewModel(); var result = viewModel.Discounts.ToDataSourceResult(request); result.Total = viewModel.Discounts.Count; return Json(result, JsonRequestBehavior.AllowGet); }public async Task<ActionResult> GetItemGroups([DataSourceRequest] DataSourceRequest request) { var queryParser = new DataSourceODataParser(); List<ItemGroupViewModel> result = await _discountService.GetItemGroups(queryParser.Parse(request)); return Json(new DataSourceResult {Data = result, Total = result.Count}, JsonRequestBehavior.AllowGet); } public async Task<ActionResult> GetItems([DataSourceRequest] DataSourceRequest request) { var queryParser = new DataSourceODataParser(); List<ItemViewModel> result = await _discountService.GetItems(queryParser.Parse(request)); return Json(new DataSourceResult {Data = result, Total = result.Count}, JsonRequestBehavior.AllowGet); } public async Task<ActionResult> GetResellers([DataSourceRequest] DataSourceRequest request) { var queryParser = new DataSourceODataParser(); List<ResellerViewModel> result = await _discountService.GetResellers(queryParser.Parse(request)); return Json(new DataSourceResult { Data = result, Total = result.Count }, JsonRequestBehavior.AllowGet); } public async Task<ActionResult> GetCustomers([DataSourceRequest] DataSourceRequest request) { var queryParser = new DataSourceODataParser(); List<CustomerViewModel> result = await _discountService.GetCustomers(queryParser.Parse(request)); return Json(new DataSourceResult { Data = result, Total = result.Count }, JsonRequestBehavior.AllowGet); }
ViewModels:
public class DiscountSettingsViewModel { public int SubscriptionId { get; set; } public List<DiscountViewModel> Discounts { get; set; } } public class DiscountViewModel { public int Id { get; set; } public ItemGroupViewModel ItemGroup { get; set; } public ItemViewModel Item { get; set; } public ResellerViewModel Reseller { get; set; } public CustomerViewModel Customer { get; set; } public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } public bool IsExtra { get; set; } public double Discount { get; set; } public DiscountViewModel() { Id = 0; ItemGroup = new ItemGroupViewModel(); Item = new ItemViewModel(); Reseller = new ResellerViewModel(); Customer = new CustomerViewModel(); IsExtra = false; Discount = 0; } } public class ItemGroupViewModel { public string Code { get; set; } public string Description { get; set; } public ItemGroupViewModel() { Code = ""; Description = ""; } } public class ItemViewModel { public string Code { get; set; } public string Description { get; set; } public ItemViewModel() { Code = ""; Description = ""; } } public class ResellerViewModel { public Guid? ID { get; set; } public string Code { get; set; } public string Name { get; set; } public Guid? Classification1 { get; set; } public ResellerViewModel() { ID = Guid.Empty; Code = ""; Name = ""; Classification1 = Guid.Empty; } } public class CustomerViewModel { public Guid? ID { get; set; } public string Code { get; set; } public string Name { get; set; } public ResellerViewModel Reseller { get; set; } public CustomerViewModel() { ID = Guid.Empty; Code = ""; Name = ""; Reseller = new ResellerViewModel(); } }
Main view:
<h2>Discount Settings</h2><script type="text/javascript"> kendo.data.binders.widget.defferedValue = kendo.data.Binder.extend({ init: function (widget, bindings, options) { kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this._change = $.proxy(this.change, this); this.widget.bind("change", this._change); }, refresh: function () { if (!this._initChange) { var widget = this.widget; var value = this.bindings.defferedValue.get(); if (value) { if (widget.options.autoBind === false) { //Bind the widget with single item if deffered binding is used widget.dataSource.data([value]); widget.value(value[widget.options.dataValueField]); } else { //set widget value directly this.widget.value(value[widget.options.dataValueField]); } } } }, change: function () { this._initChange = true; this.bindings.defferedValue.set(this.widget.dataItem() || null); this._initChange = false; }, destroy: function () { this.widget.unbind("change", this._change); } });</script>@(Html.Kendo().Grid<DiscountViewModel>() .Name("Discounts") .Columns(col => { col.Bound(i => i.ItemGroup) .Title(Resource.ItemGroup) .ClientTemplate("#: data.ItemGroup ? data.ItemGroup.Code : '[none]' #") .EditorTemplateName("ItemGroupLookup") .Filterable(false) .Sortable(true); col.Bound(i => i.Item) .Title(Resource.Item) .ClientTemplate("#: data.Item ? data.Item.Code : '[none]' #") .EditorTemplateName("ItemLookup") .Filterable(false) .Sortable(true); col.Bound(i => i.Reseller) .Title(Resource.Reseller) .ClientTemplate("#: data.Reseller ? data.Reseller.Name : '[none]' #") .EditorTemplateName("ResellerLookup") .Filterable(false) .Sortable(true); col.Bound(i => i.Customer) .Title(Resource.Customer) .ClientTemplate("#: data.Customer ? data.Customer.Name : '[none]' #") .EditorTemplateName("CustomerLookup") .Filterable(false) .Sortable(true); col.Bound(i => i.StartDate).Title(Resource.StartDate).Format("{0:dd-MM-yyyy}"); col.Bound(i => i.EndDate).Title(Resource.EndDate).Format("{0:dd-MM-yyyy}"); col.Bound(i => i.IsExtra).Title(Resource.IsExtra); col.Bound(i => i.Discount).Title(Resource.Discount); col.Command(command => { command.Edit().Text(Resource.Edit); command.Destroy().Text(Resource.Delete); }).Width(250); }) .Sortable(s => s.SortMode(GridSortMode.MultipleColumn)) .ToolBar(toolbar => toolbar.Create().Text(Resource.Add)) .Editable(editable => editable.Mode(GridEditMode.InLine)) .Pageable() .DataSource(source => source .Ajax() .PageSize(20) .Events(events => events.Error("error_handler")) .Model(m => { m.Id(i => i.Id); m.Field(p => p.ItemGroup); m.Field(p => p.Item); m.Field(p => p.Reseller); m.Field(p => p.Customer); m.Field(p => p.StartDate); m.Field(p => p.EndDate); m.Field(p => p.IsExtra); m.Field(p => p.Discount); }) .Create(update => update.Action("CreateSetting", "Settings")) .Read(read => read.Action("GetSettings", "Settings")) .Update(update => update.Action("UpdateSetting", "Settings")) .Destroy(update => update.Action("DestroySetting", "Settings")) ) .NoRecords(Resource.NoSettings))
Example EditorTemplate:
@model NuCall.ViewModels.ItemGroupViewModel@(Html.Kendo().DropDownListFor(m => m) .HtmlAttributes(new { data_skip = "true", data_bind = "deferredValue: ItemGroup" }) .OptionLabel("--none--") .DataSource(source => { source.Custom() .ServerFiltering(true) .ServerPaging(true) .PageSize(20) .Type("aspnetmvc-ajax") .Transport(transport => transport.Read("GetItemGroups", "Settings")) .Schema(schema => schema .Data("Data") .Total("Total") .Errors("Errors")); }) .MinLength(1) .AutoBind(false) .Filter(FilterType.StartsWith) .DataValueField("Code") .DataTextField("Code"))