Kendo grid prevent server side filtering? - asp.net-mvc

I have simple Kendo-Grid configuration as below (Mvc project)
#(Html.Kendo().Grid<ReviewModel>()
.Name("grid")
.DataSource(dataSource => dataSource
.Custom()
.PageSize(20)
.Schema(schema => schema.Model(m => m.Id(p => p.Id)))
.Transport(transport =>
{
transport.Read("ReadData");
})
) .Columns(columns =>
{
columns.Bound(m => m.Id).Visible(false);
columns.Bound(m => m.Code).Width(110).Filterable(ftb => ftb.Cell(cell =>
{
cell.Operator("contains");
cell.ShowOperators(false);
}));
columns.Bound(m => m.Name).Filterable(ftb => ftb.Cell(cell =>
{
cell.Operator("contains");
cell.ShowOperators(false);
}));})
.Filterable(ftb => ftb.Mode(GridFilterMode.Row))
.Pageable(p => p.Enabled(true).Info(false).Input(true).Numeric(false)))
Also do little ajax call for loading data
function ReadData(options) {
var option = {
url: '/read',
dataType: 'json',
data: {
id: '44',
type: '5'
}
};
$.ajax(option).success(function (data) {
options.success(data);
}).error(function (e) {
console.debug(e);
options.error(e);
});
}
As result everything work perfectly. grid loaded on page(Mvc partial), and then get data from server(Mvc action) and show it well.
But for first time (in each column) if user change filter of column grid call read again, and ajax call occurred. I want to prevent to call server for filtering or other things? is that possible?

Related

mvc Kendo grid with an kendo autocomplete column not working

I'm trying to add an kendo autocomplete column to my kendo grid and its not working. I tried using the telerik example with a datasource function instead of view bag as there will be lots of data to pull from.
i used an kendo autocomplete widget outside the grid and it worked. all i need is to get it to work on the grid column.
i tried the editor templates and its not working. i cant even see the column "Vendor" appearing on the grid.Here's my code.
#(Html.Kendo().Grid<Budget.ProductFieldsTRC>().Name("GridProductsTrc").Columns(columns =>{columns.Bound(p => p.ValidationErrors).Title("Validation Errors").Width(300);columns.Bound(p => p.VendorNo).Title("Vendor No").Width(250);columns.Bound(p => p.Vendor).EditorTemplateName("VendorEditor");columns.Bound(p => p.VendorName).Title("Vendor Name").Width(250);columns.Bound(p => p.Project).Title("Project").Width(250);columns.Bound(p => p.ZZZValue).Title("Prefix").Width(250);columns.Bound(p => p.Manf).Title("Manf").Width(250);columns.Bound(p => p.Type).Title("Type").Width(250);columns.Bound(p => p.Component).Title("Component").Width(250);columns.Bound(p => p.Description).Title("Description").Width(250); columns.Command(command =>
{
command.Edit();
}
)
.Width(200);
})
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Navigatable()
.Pageable()
.Filterable(ftb => ftb.Mode(GridFilterMode.Row))
.Selectable(selectable => selectable
.Mode(GridSelectionMode.Multiple)
.Type(GridSelectionType.Cell))
.HtmlAttributes(new { style = "height:400px" })
.Resizable(conf => conf.Columns(true))
.Scrollable()
.Pageable(pager => pager
.PageSizes(true)
.Messages(messages => messages.ItemsPerPage("items are currently displayed"))
)
.Reorderable(reorder => reorder.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error_handler"))
.Update(update => update.Action("UpdateGridTrc", "Customer"))
.PageSize(20)
.Model(model =>
{
model.Id(x => x.RowID);
model.Field(fld => fld.VendorNo).Editable(true);
model.Field(fld => fld.Vendor).Editable(true);
model.Field(fld => fld.VendorName).Editable(true);
model.Field(fld => fld.Project).Editable(true);
model.Field(fld => fld.ZZZValue).Editable(true);
model.Field(fld => fld.Manf).Editable(true);
model.Field(fld => fld.Type).Editable(true);
model.Field(fld => fld.Component).Editable(true);
model.Field(fld => fld.Description).Editable(true);
model.Field(fld => fld.ValidationErrors).Editable(false);
})
.Read(read => read.Action("ViewProductGridTRC", "Customer"))
)
)
MY EDITOR TEMPLATE -in the views/ shared/ editor template folder - called VENDOREDITOR
#model string#(Html.Kendo().AutoComplete().Name("Vendor").DataTextField("VendorName").Placeholder("Type a vendor name").Template("#= VendorNo # | For: #= VendorName #").ValuePrimitive(true).Filter("contains").MinLength(1).DataSource(source =>{source.Read(read =>{read.Action("GetVendorList", "Customer").Data("onAdditionalData");}).ServerFiltering(true);}))
my filtering method for the autocomplete onAdditionalData method
function onAdditionalData() {
return {
text: $("#Vendor").val()
};
}
MY CONTROLLER ACTION METHOD FOR THE AUTOCOMPLETE DATASOURCE
public JsonResult GetVendorList(string text)
{
var result = GetVendors();
if (!string.IsNullOrEmpty(text))
{
result = result.Where(p => p.VendorName.Contains(text)).ToList();
}
return Json(result, JsonRequestBehavior.AllowGet);
}
AND
private static IEnumerable<Vendor> GetVendors()
{var result = Enumerable.Range(0, 10).Select(i => new Vendor{VendorNo = "" + i,VendorName = "Vendor " + i}); return result;
}

How do I use different datasources for kendo UI grid?

I'm not too familiar with Kendo and have watched some tutorials but even following exactly I do not get the same result. I made a page using cached data and pass it as a datasource to the grid in different ways.
In this code, the read method is not being called at all. I have no idea why.
#(Html.Kendo().Grid<TestCategory>().Name("TCategory1").Columns(c =>
{
c.Bound(p => p.Name);
c.Bound(p => p.Id);
})
.DataSource(d => d.Ajax().Read(r => r.Action("Read", "Category").Type(HttpVerbs.Get))
.PageSize(3))
.Pageable()
.Sortable()
.Filterable()
)
In the second grid, I am able to get the data to display but not able to edit
#(Html.Kendo().Grid(Model).Name("TCategory").Columns(c =>
{
c.Bound(p => p.Name);
c.Bound(p => p.Id);
c.Command(com => { com.Edit(); com.Destroy(); });
})
.DataSource(d => d.Ajax().ServerOperation(false).PageSize(3)
.Update(u => u.Action("Edit", "Category"))
.Create(c => c.Action("Create", "Category"))
.Destroy(c => c.Action("Delete", "Category"))
.Model(m => { m.Id(p => p.Id); })
)
.Pageable().Editable(e => e.Mode(GridEditMode.InCell)).Sortable().Filterable().ToolBar(t => t.Create()) )
Read method:
[HttpPost]
public JsonResult Read([DataSourceRequest]DataSourceRequest request)
{
IQueryable<TestCategory> cat = context.Collection();
return Json(cat.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

kendo ui "Invalid template" error in a column client template within a detail template

I have a grid with a client detail template. This detail template is rendered in a separate partial view. Within this grid I need to use client templates to format some of the columns. Unfortunately I run into an invalid template error.
This is my detail template:
<script id="operationDetailTemplate" type="text/kendo-template">
#(Html.Kendo().TabStrip()
.Name(componentName: "tabStrip_#=Id#")
.SelectedIndex(index: 0)
.Animation(animation => animation.Open(open => open.Fade(FadeDirection.In)))
.Items(items => {
items.Add().Text(this.LocalResources(key: "Messages")).Content(#<text>
#(Html.Kendo().Grid<NotificationViewModel>()
.Name(componentName: "notificationGrid_#=Id#")
.Pageable()
.Scrollable()
.Filterable()
.Sortable()
.Columns(col => {
col.Bound(c => c.DateCreated).Format(value: "{0:yyyy/MM/dd HH:mm}");
col.Bound(c => c.Severity);
col.Bound(c => c.Title);
col.Bound(c => c.Text).ClientTemplate(string.Format("{0}...", "#= formatter(Text, 20) #"));
})
.DataSource(ds => ds.Ajax().Sort(sort => sort.Add(memberName: "DateCreated").Descending())
.Read(read => read.Route(MessageEventControllerRoute.PostReadForOperation, new RouteValueDictionary { { "operationId", "#=Id#" }, { "culture", UICulture.ToLower() } })))
.ToClientTemplate())
</text>
);
items.Add().Content(#<text>
#(Html.Kendo().Grid<OperationViewModel>().Name(componentName:"alternativesGrid")
.Columns(col => {
col.Bound(op => op.OperationIdFormatted);
col.Bound(op => op.EfficiencyRank);
col.Bound(op => op.WorkOrder.WorkOrderIdFormatted);
col.Bound(op => op.Length)
.ClientTemplate(value: "#if (data.Length) {# #:kendo.toString(Length.Hours, '00')#:#:kendo.toString(Length.Minutes, '00')#:#:kendo.toString(Length.Seconds, '00')# #}#")
.EditorTemplateName(templateName: "TimeSpan");
})
.DataSource(ds => ds.Ajax()
.Read(read => read.Route(OperationControllerRoute.PostOperationAlternatives, new RouteValueDictionary { { "workOrderId", "#=Operation.WorkOrderId#" }, { "seqNo", "#=Operation.SequenceNumber#" }, { "culture", UICulture.ToLower() } })).Model(m => m.Id(op => op.Id)))
.ToClientTemplate()
)</text>);
})
.ToClientTemplate())
</script>
As I am not able to pass an template id to the column template, I have no idea how to avoid the invalid template error.
Any ideas how to use client templates in this scenario?
Regards
Bernd
After some more experimenting I found two solutions.
Escape the client template in the low level grid.
Using
.ClientTemplate(value: "\\#if (data.Length) {\\# \\#:kendo.toString(Length.Hours, '00')\\#:\\#:kendo.toString(Length.Minutes, '00')\\#:\\#:kendo.toString(Length.Seconds, '00')\\# \\#}\\#")
instead of
.ClientTemplate(value: "#if (data.Length) {# #:kendo.toString(Length.Hours, '00')#:#:kendo.toString(Length.Minutes, '00')#:#:kendo.toString(Length.Seconds, '00')# #}#")
Change the tab content to load on demand.
Only problem here is that the ajax data source isn't called. So pass a model to the partial view and remove the
.ToClientTemplate()
instruction.

Kendo MVC: Adding Edit, Delete Buttons to Grid

Assuming I have the below table:
#Html.Kendo().Grid(Model).Name("Staff").Columns(x =>
{
x.Bound(y => y.StaffId);
x.Bound(y => y.FirstName);
x.Bound(y => y.LastName);
x.Bound(y => y.Email);
x.Bound(y => y.Phone);
x.Command(y => y.Custom("Edit").Action("edit", "controller", new { id = ????? }));
}).Sortable().Scrollable().Pageable(x=> x.PageSizes(true)).Filterable()
How can I pass the primary key value (StaffId in this case) associated to the row to the object route values similar to the way it is done by Visual Studio auto-scaffold?
I do not know if you can pass ID using Command.Custom the way you are attempting right now.
If you prefer this way, you can define a JS method and fetch selected row in that and perform an AJAX operation to manipulate the data.
So in your case you can instead define command as:
columns.Command(command => command.Custom("Edit").Click("editRow"));
and in script tag, you can define method that read and send data to server:
function editRow(e) {
e.preventDefault();
try {
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var searchId = dataItem.Id;
var searchName = dataItem.Name;
var model = { searchId: searchId };
$.ajax({
url: '#Url.Action("BindLeftMenu")',
contentType: 'application/json; charset=utf-8',
type: 'POST',
dataType: 'html',
data: JSON.stringify(model)
})
.success(function (resultMenu) {
$("#driversummaryarea").show();
})
.error(function (xhr, status) {
$("div.overlay").hide();
});
}
catch (e) {
alert(e.message);
}
}
Now there are 2 other ways you can modify grid data:
Use default commands e.g. Edit(). A demo is shown here. Simple and easy but limiting i.e. less control from JS.
Use ClientTemplate - Very powerful as offers full control over display and capturing data in JS.
For example with ClientTemplate you can define a grid like below. Notice how we are passing model Id parameter in ClientTemplate as raw html.
Once you define ClientTemplate, you can define the JS functions fnEditUser as shown above and perform operation on grid data.
HTML
#(Html.Kendo().Grid<Eda.RDBI.Web.Models.OrganizationUserViewModel>()
.Name("organizationUserViewModelGrid")
.Columns(columns =>
{
columns.Bound(p => p.FirstName).Filterable(true).Title("Name").Groupable(false).ClientTemplate("<a class='lnkEditUser' href='javascript:void(0)' onclick='fnEditUser(#=Id#)' > #=FirstName# </a>").Width(200);
columns.Bound(p => p.EMail).Width(200);
columns.Bound(p => p.Role)
.ClientTemplate("<span>#=Role#</span> <span>#=IsDriverSearchAllowed ? ' (DS)' : ''#</span>");
columns.Bound(p => p.IsActive).Title("Active")
.ClientTemplate("<input type='checkbox' #=IsActive ? checked='checked':'' # class='chkbx' onclick='return false'/>");
columns.Bound(p => p.Id).Title(string.Empty).ClientTemplate("<a class='btn btn-default' href='javascript:void(0)' onclick='fnDeleteUser(#=Id#)'>Delete</a>").Filterable(false).Sortable(false);
})
.Sortable(sortable => sortable.AllowUnsort(false))
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(50)
.Model(model => model.Id(p => p.Id))
.Read(read => read.Action("GetUsersForOrganization", "OrganizationUser"))
)
.Scrollable(scrollable => scrollable.Virtual(true))
)
This works for me. If you're not doing any AJAX, you might be able to just move the anchor into Template and not use ClientTemplate. I'm using bootstrap buttons, but you could replace that code with your own styles or the kendo styles.
This is the code that inserts your id: #= Id # - it should be a field from your Model. See http://docs.telerik.com/kendo-ui/framework/templates/overview
#Html.Kendo().Grid(Model).Name("Staff").Columns(x =>
{
x.Bound(y => y.StaffId);
x.Bound(y => y.FirstName);
x.Bound(y => y.LastName);
x.Bound(y => y.Email);
x.Bound(y => y.Phone);
x.Template(#<text></text>).Title(string.Empty).Width(40)
.ClientTemplate(#"<a href='" + Url.Action("Edit") + "?id=#= Id #' class='btn btn-info btn-xs' title='Modify this'>Edit</a>");
}).Sortable().Scrollable().Pageable(x=> x.PageSizes(true)).Filterable()
After playing with the grid over and over, I could finally solve the problem. Here you go:
x.Bound(y => y.Title).Template(y=> "Click Me")

kendo ui grid repeat the destroy action on error

I have a grid similar to the code below.
if an errors occurs on destroy action they accumulate.
for example the on the first error 1 call to destroy action, the second 2 calls, the third error 3 calls .......
after some investigation I found out that the items to be sleeted are stored in an array (_destroyed) in the dataSource,
so every time the destroy button is clicked the destroy action is called for each of these items.
I tried assigning null to the _destroyed array but this gave js error when I called destroy action again.
#(Html.Kendo().Grid<someType>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.Name);
columns.Command(command =>
{
command.Edit();
command.Destroy();
}).Width(250);
})
.Editable(editable => { editable.Mode(GridEditMode.PopUp); editable.TemplateName("myTemplate"); })
.Pageable()
.Sortable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(50)
.Events(events => events.Error("error_handler"))
.Model(model => model.Id(p => p.Id))
.Create(update => update.Action("EditingPopup_Create", "myController"))
.Read(read => read.Action("EditingPopup_Read", "myController"))
.Update(update => update.Action("EditingPopup_Update", "myController"))
.Destroy(update => update.Action("EditingPopup_Destroy", "myController"))
)
<script type="text/javascript">
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
alert(message);
$(".k-grid").each(function () {
var grid = $(this).data("kendoGrid");
if (grid !== null && grid.dataSource == e.sender) {
grid.one('dataBinding', function (e) {
e.preventDefault();
});
grid.dataSource.read();
grid.refresh();
}
});
}
}
</script>
a
You can call the cancelChanges method of the data source and then read. There is no need to call grid.refresh() as it will be called automatically when dataSource.read() is done.
Ok I'm not sure If that's a legitimate answer but this fixed my problem
grid.dataSource._destroyed = [];
grid.dataSource.read();
grid.refresh();
I hope it saves some's time.

Resources