Using Kendo-UI grid for asp.net MVC, with multi-checkbox filtering, how do I configure data source for limiting options returned by the server? - kendo-ui

I'm working with a Kendo-UI grid for asp.net MVC (version 2022.2.621.545) and I added multi-checkbox filtering to the columns. The grid items are pulled from the server using a configured ajax call to a controller action, and clicking on a filter button triggers another call to retrieve the full set of items in order to build the checkbox list. In some cases there are too many items returned and the grid appears to hang trying to determine the unique items for the checkbox list.
I was wondering if lazy loading can be configured for multi-checkbox filtering such that paging info is sent to the data source controller action. Alternatively, I've read that there may be a way to hold off on retrieving items for the filter until a minimal search string has been entered, with the search string being sent to the data source controller action.
I've looked at Kendo-UI documentation for multi-checkbox filtering options, but nothing has been abundantly clear that what I need to do is possible, especially within the asp.net MVC directives. I'm hoping someone can provide some guidance as to how to modify my grid setup to configure additional control for retrieving filter options. This is my current working code:
<div style="height:690px" id="warehouseGrid">
#(Html.Kendo().Grid<WarehouseModel>()
.Name("inventoryGrid")
.HtmlAttributes(new { style = "height:100%; width: 100%;" })
.Columns(columns =>
{
columns.Bound("InventoryLineItemID").Title("").Width(35).Filterable(false).ClientTemplate(
"<img src='https://cdn.host/show_detail.png' class='k-icon k-delete' height='45' width='45' onclick='ShowInventoryItemDetails(\"#= InventoryLineItemID #\")' onmouseover='' style='cursor: pointer;' title='Show Inventory Item Details' alt='Show Inventory Item Details' />"
);
foreach (WarehouseField col in fields)
{
if (!string.IsNullOrEmpty(col.Template))
{
columns.Bound(col.PropertyName).Title(col.Title).Width(col.Width).Filterable(false).ClientTemplate(col.Template);
}
else
{
columns.Bound(col.PropertyName).Title(col.Title).Width(col.Width).Filterable(ftb => ftb.Multi(true).Search(true));
}
}
})
.Pageable(pager => pager.PageSizes(new[] { 10, 20, 50, 100 }))
.Excel(excel => excel
.AllPages(true)
)
.ToolBar(
toolbar =>
{
toolbar.Template(#<text>
#ToolbarTemplate()
</text>);
}
)
.Events(e => e.DataBinding(#<text>function(e) { onDataBinding(this) }</text>))
.Events(e => e.DataBound(#<text>function(e) { onDataBound(this) }</text>))
.Resizable(r => r.Columns(true))
.ColumnResizeHandleWidth(5)
.Scrollable()
.Sortable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(100)
.Read(read => read.Action("GetInventory", "Warehouse", new { area = "Rest" }).Data("additionalData"))
)
)
</div>

Related

Batch save Kendo Grid in Inline edit mode

I have a MVC3 Razor View for a simple Contact entity - first and last name, job title etc - including a grid being used to save one or more phone numbers.
The grid appears setup in inline edit mode after the user clicks save to create a new item, and there is a new Id to save phone numbers against. This works okay but the client would prefer that the whole form is saved on that first click, including any edits to the phone number grid. The tricky bit is they want to keep the existing inline UX, which is where my question lies:
How can you keep all the UI/UX associated with the kendo grid inline editing mode, but save as a batch, as you would if it were set to in-cell editing?
I have read various articles and tutorials to do with saving grid changes on click, but most are specific to in-cell editing and are not specific to Razor.
Here is the code for the grid as it stands (no editor template or js functions), please let me know if I can provide any further detail and I will update my question.
#(Html.Kendo().Grid<ContactNumberListItem>()
.Name("PhoneNumbersGrid")
.Columns(columns =>
{
columns.Bound(model => model.Number).Title("Number").Format("{0:#,#}");
columns.Bound(model => model.Type).EditorTemplateName("_tmpl_contactPhoneNumberType_dd").Title("Type").ClientTemplate("#:Type.Name#");
columns.Command(commands =>
{
commands.Edit().Text(" ")
.UpdateText(" ")
.CancelText(" "); // The "edit" command will edit and update data items
commands.Custom("Delete").Text(" ").Click("DeleteContactPhoneNumber"); // The "destroy" command removes data items
}).Width(98);
})
.ToolBar(toolBar => toolBar.Create())
.Editable(editable => editable.Mode(GridEditMode.InLine).DisplayDeleteConfirmation(false))
.Selectable()
.Events(events => events
.DataBound("OnGridDataBound")
.Cancel("OnGridCancel")
.Edit("OnGridEdit")
.Save("OnGridSave"))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(false)
.PageSize(5)
.ServerOperation(false)
.Model(model =>
{
model.Id(x => x.Id);
model.Field(t => t.Type).DefaultValue(((List<PhoneNumberTypeListItem>)ViewBag.ContactPhoneNumberTypes).FirstOrDefault());
})
.Create(update => update.Action("CreateContactPhoneNumber", "ContactPhoneNumber").Data("GetContactId"))
.Update(update => update.Action("UpdateContactPhoneNumber", "ContactPhoneNumber"))
.Read(read => read.Action("SelectContactPhoneNumbers", "ContactPhoneNumber").Data("GetContactId"))
.Events(e => e.Error("error_handler"))))
The answer seems to be to use placeholder controller methods for create/update/delete - that is, methods that do not do anything - then follow use the code below to submit to the controller on whatever click or action:
http://www.telerik.com/support/code-library/save-all-changes-with-one-request

Kendo UI Grid returns JSON to browser (using MVC)

I've recently purchased a Kendo subscription, I'm having trouble getting an AJAX bound grid to operate as expected, hoping someone here can help.
I have followed the Kendo docs tutorial # http://docs.kendoui.com/getting-started/using-kendo-with/aspnet-mvc/helpers/grid/ajax-binding
and could get the AJAX binding working nicely.
I've tried to now implement it into an existing MVC solution, and whenever I click the New or Edit command button, I get a string of JSON returned to the browser. Similiar to issue (JSON data to KENDO UI Grid ASP.NET MVC 4) But the answer in that problem didn't work for me.
Here is my Controller code...
public ActionResult Index()
{
// non-important code removed here //
var viewModel = newReferenceViewModel();
ViewBag.TradeReferences = TradeReferenceWorker.Get(applicationId);
return View(viewModel);
}
public ActionResult TradeReferences_Read([DataSourceRequest]DataSourceRequest request)
{
var applicationId = GetCurrentApplicationId();
DataSourceResult result = TradeReferenceWorker.Get(applicationId).ToDataSourceResult(request);
return Json(result, "text/x-json", JsonRequestBehavior.AllowGet);
}
And the View ....
#(Html.Kendo().Grid((IEnumerable<TradeReference>)ViewBag.TradeReferences)
.Name("gridTradeReference")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(tradeReference => tradeReference.TradeReferenceId);
model.Field(tradeReference => tradeReference.TradeReferenceId).Editable(false);
})
.Read(read => read.Action("TradeReferences_Read", "References"))
.Create(create => create.Action("TradeReference_Create", "References"))
.Update(update => update.Action("TradeReference_Update", "References"))
.Destroy(destroy => destroy.Action("TradeReference_Destroy", "References"))
)
.Columns(columns =>
{
columns.Bound(tref => tref.TradeReferenceId).Visible(false);
columns.Bound(tref => tref.Name);
columns.Bound(tref => tref.Phone);
columns.Command(commands =>
{
commands.Edit();
commands.Destroy();
}).Title("").Width(200);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Sortable()
)
So to sum up... the Grid will load perfectly the first time. I haven't wired up anything on the Edit / Delete actions, just trying to get Create operational. Clicking Add New, or even Edit for that matter will make the browser simply display Json to the screen.
It is hopefully something simple - thanks in advance
Solved it - the problem was the kendo js files were not being referenced correctly.
In my particular case, the bundling wasn't done 100% correctly so the Kendo javascript files were never getting included in the page.
They must also appear in a certain order, as described in the troubleshooting guide http://docs.kendoui.com/getting-started/using-kendo-with/aspnet-mvc/helpers/grid/troubleshooting

Kendo UI ASP.Net MVC ForeignKey column DataSource in InCell Edit mode

I have Kendo Grid and a ForeignKey column on a page. ForeignKey column is populated using ViewData as described below.
column.ForeignKey(x => x.ProductID, (List<Product>)ViewData["products"], "ID", "ProdName");
The Grid is editable in batch(InCell) mode as show below...
.Editable(editable => editable.Mode(GridEditMode.InCell)
I want to modify collection of ProductID column in the grid after page is loaded based on value selected on other drop-down defined outside of the Grid.
How can I achieve that? Can I do it using jQuery?
Similar example I found here...
http://www.telerik.com/community/forums/aspnet-mvc/grid/cascading-dropdowns-in-grid-edit---foreignkey-columns.aspx
Thanks.
I figured out how to filter the Product drop-down using an EditorTemplate for the foreign key column.
Here is my column definition for the Product.
c.ForeignKey(x => x.ProductID, (List<Product>)ViewData["products"], "ID", "ProdName").EditorTemplateName("ProductIDEditor");
Here is the editor template for Product, ProductIDEditor.cshtml
#using Kendo.Mvc.UI
#(Html.Kendo().DropDownListFor(m => m)
.AutoBind(false)
.OptionLabel("Select a value...")
.DataTextField("ProdName")
.DataValueField("ID")
.DataSource(dataSource =>
{
dataSource.Read(read => read.Action("FilterProducts", "Home").Data("filterProducts"))
.ServerFiltering(true);
})
)
#Html.ValidationMessageFor(m => m)
In my main VIEW Index.cshtml, I added filterProducts JavaScript handler, that passes JSON object for productID to controller.
function filterChargeTypes()
{
return {
productID: $("#ProductID").val()
};
}
Here is the controller that listens to filtering event...
public ActionResult FilterProducts(string productID)
{
// do your filtereing based on productID.
}
FilterProducts will be called every time when user hits the drop-down to get filtered value.
You don't need the Editor Template. It will bind to a dropdown without it. You can use this, like you had, just minus the template:
c.ForeignKey(x => x.ProductID, (List<Product>)ViewData["products"], "ID", "ProdName")
or
c.ForeignKey(x => x.ProductID, (System.Collections.IEnumerable)ViewData["products"], dataFieldValue: "ID", dataFieldText: "ProdName")
And for filtering, you can just invoke .Filterable() on the grid.

Kendo UI ASP.NET MVC grid datasource filters value is null

I am trying to dynamically add grid filters in my view using the html helper via datasource configuration, like this example from the kendo documentation:
#(Html.Kendo().Grid<Product>()
.Name("grid")
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Products_Read", "Home"))
.Filter(filters =>
{
if (someCondition){
// Show products whose ProductName property contains "C"
filters.Add(product => product.ProductName).Contains("C");
// and UnitsInStock is greater than 10
filters.Add(product => product.UnitsInStock).IsGreaterThan(10);
}
})
)
)
The filters are added, but the filterdescriptor.Value in each case is always null (the Member and Operator are fine).
Any help much appreciated.
Thanks!
--Berry
Make sure you have included kendo.aspnetmvc.min.js. Missing it would lead to similar symptoms.

Telerik RadGrid CustomSorting without hitting database?

I tried to post on Telerik forum, but now each time I try to open my thread, I get
"Oops...
It seems there was a problem with our server."
So I posted this question here.
I am pretty new to Telerik and RadGrid. I am trying to modify existing project because client needs custom sorting. There is a data field which may contain numbers or text so it is a string type but sometimes it has to be sorted as numbers. So I went to this link:
http://demos.telerik.com/aspnet-ajax/grid/examples/programming/sort/defaultcs.aspx
and
http://www.telerik.com/help/aspnet-ajax/grdapplycustomsortcriteria.html
The example says:
"With custom sorting turned on, RadGrid will display the sorting icons but it will not actually sort the data."
but it seems it is not enough to add AllowCustomSorting to disable default sorting.
When implementing SortCommand, I noticed that I have to do
e.Canceled = true;
because else default sorting occurs. Why this is not mentioned in the documentation nor example?
But the main question is - inside of SortCommand my RadGrid already has all items loaded. So is there any way to sort them to avoid hitting database? I tried accessing various Items properties of both "object source, GridSortCommandEventArgs e", but all Items are read-only, so I cannot sort them and attach back to the RadGrid.
Thanks for any ideas.
You can set the sortExpression in the OnSelecting event of the objectDatasource and use it in the SelectMethod.
protected void odsGridData_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
e.InputParameters["filterExpression"] = grdMyTasks.MasterTableView.FilterExpression;
//Set the Sort Expression and use this in the Get method
e.InputParameters["sortExpression"] = grdMyTasks.MasterTableView.SortExpressions.GetSortString();
e.Arguments.StartRowIndex = grdMyTasks.CurrentPageIndex;
e.Arguments.MaximumRows = grdMyTasks.PageSize;
}
This way you can perform custom sort and pass on the data to the RadGrid.
Hope this helps.
Here is an example of some code I use that does not hit the database. I'm using MVC 3 with the Razor view engine. Notice the Ajax binding. Don't forget to add using Telerik.Web.Mvc.UI and annotate the "Post" methods in your controller with [GridResult] and to return GridModel to get the Json resultset.
using Telerik.Web.Mvc;
[GridAction]
public ActionResult AjaxGridSelect()
{
return View(new GridModel(db.lm_m_category));
}
Here is the index.cshtml (razor engine), the key is the Ajax binding.
#model IEnumerable<LinkManagerAdmin.Dal.lm_r_category>
#using Telerik.Web.Mvc.UI
#(Html.Telerik().Grid(Model)
.Name("Grid")
.DataKeys(keys => keys.Add(c => c.category_id ))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("AjaxGridSelect", "CategoryTree")
.Insert("GridInsert", "CategoryTree", new { GridEditMode.PopUp, GridButtonType.ImageAndText })
.Update("GridUpdate", "CategoryTree", new { GridEditMode.InLine, GridButtonType.ImageAndText })
.Delete("GridDelete", "CategoryTree", new { GridEditMode.InLine, GridButtonType.ImageAndText }))
.Columns(columns =>
{
columns.Bound(p => p.category_name).Width(150);
columns.Bound(p => p.status_cd).Width(100);
columns.Command(commands =>
{
commands.Edit().ButtonType(GridButtonType.ImageAndText);
commands.Delete().ButtonType(GridButtonType.ImageAndText);
}).Width(180).Title("Commands");
})
.Editable(editing => editing.Mode(GridEditMode.InLine))
.Pageable(paging => paging.PageSize(50)
.Style(GridPagerStyles.NextPreviousAndNumeric)
.Position(GridPagerPosition.Bottom))
.Sortable(o => o.OrderBy(sortcol =>
{
sortcol.Add(a => a.category_name);
sortcol.Add(a => a.add_date);
})
.Filterable()
.Groupable()
.Selectable())

Resources