I have this grid with a custom multi-select filter. When I click the filter icon an AJAX method calls an API to grab filter values. The method call is defined in the DocType column.
Here is my grid builder function:
$("#attachmentsGrid").kendoGrid({
pageable: {
change: function() {
CH.RelatedItems.GridPager();
}
},
scrollable: false,
sortable: true,
dataSource: attachments,
filterable: {
extra: false,
operators: {
string: {
startswith: "Starts with",
eq: "Is equal to",
neq: "Is not equal to",
contains: "Contains",
}
}
},
columns:
[
{
title: "id",
field: "Id", //turns out this needs to be lower case
sortable: false,
filterable: false,
template: "<input name='cbCheckboxColumn' type='checkbox' onclick='CH.RelatedItems.ToggleAttachmentsByCheckboxColumn()' data-row='#: Id#' />",
headerTemplate: "<input id='cbCheckboxHeader' type='checkbox' onclick='CH.RelatedItems.ToggleAttachmentsByCheckboxHeader()'",
width: "18px",
},
{
title: "Exists?",
field: "IsAlreadyAttached",
type: "boolean",
sortable: false,
template: "<div style='text-align: center'>#: IsAlreadyAttached #</div>",
filterable: false,
width: "110px",
},
{
title: "Icon",
field: "DocType",
sortable: true,
template: "<div style='text-align: center'><img src='" + config.SPHostUrl + "/_layouts/images/#: DocIcon #' /></div>",
width: "60px",
filterable: {
ui: CH.RelatedItems.AttachmentsIconFilter,
extra: false,
},
},
{
title: "File Name",
field: "Name",
sortable: true,
filterable: false,
template: "<a href='#: Url#' target='_blank'>#: Name#</a>",
width: "650px",
},
{
title: "Modified",
field: "LastModifiedDateOnly",
template: "<span>#: LastModified#</span>",
sortable: true,
width: "250px",
filterable: {
ui: CH.RelatedItems.AttachmentsDateFilter,
extra: false
}
},
],
dataBound: CH.RelatedItems.PostGridDataBound
});
The AttachmentsIconFilter function is here:
pub.AttachmentsIconFilter = function (element) {
var menu = $(element).parent();
menu.find(".k-filter-help-text").text("Show document types:");
menu.find("[data-role=dropdownlist]").remove();
var multiSelect = element.kendoMultiSelect({
dataSource: {
transport: {
read: {
datatype: "jsonp",
url: config.WorkPaperViewRelativePath + "/_RelatedItemsPopup/GetAttachmentsUniqueDocIcons/" + config.SPQueryString
}
}
},
}).data("kendoMultiSelect");
menu.find("[type=submit]").on("click", { widget: multiSelect }, CH.RelatedItems.AttachmentsFilterByIcon);
}
When the AttachmentsIconFilter runs, the AJAX call get made twice:
Kendo Double GET
I thought that the property: filter: { extra: false } was supposed to prevent this double GET?
Also, when I select my filters and the grid make a new request to get the filtered records, it does a double POST. The function for the call to filter the grid is here:
pub.AttachmentsFilterByIcon = function (e) {
var icons = e.data.widget.value();
var filter = { logic: "or", filters: [] };
for (var i = 0; i < icons.length; i++)
{
filter.filters.push({ field: "DocIcon", operator: "Contains", value: icons[i].Contains });
}
$("#attachmentsGrid").data("kendoGrid").dataSource.filter(filter);
}
Any help here? What am I missing?
Related
I am new to kendoUI and I need some assistance with getting the data that is returned from a function to populate into the dropdown. I am currently getting [object HTMLSelectElement] - you can see in the image attached. Any help is appreciated.
data is returned in function
dropdown is not showing the years returned
LoadAcceptedSubmissionsGrid: function (module) {
// Grid for "Accepted" tab
var isAccepted = "true";
gridAcceptedSubmissions = $("#gridAcceptedSubmissions").kendoGrid({
dataSource: {
type: "json",
serverPaging: true,
serverSorting: true,
serverFiltering: true,
allowUnsort: true,
transport: {
read: function (options) {
var strFilter = JSON.stringify(options.data.filter);
var strSort = JSON.stringify(options.data.sort);
var pageSize = options.data.pageSize === undefined && gridAcceptedSubmissions !== null ?
gridAcceptedSubmissions.dataSource.total() :
options.data.pageSize;
var acceptedSubmissionsUrl = commonUrl + "/Forms/Submissions/"
+ upacsSessionId + "/" + userId + "/" + form + "/" + isAccepted + "/"
+ options.data.page + "/" + pageSize + "/" + options.data.skip;
$.ajax({
type: "POST",
url: acceptedSubmissionsUrl,
xhrFields: {
withCredentials: true
},
data: {
filter: strFilter,
sort: strSort
},
success: function (response) {
options.success(response);
},
error: function (result) {
options.error(result);
}
});
}
},
pageSize: 10,
batch: false,
schema: {
total: function (response) {
return response.total;
},
data: function (response) {
return response.values;
},
model: {
id: "submissionId",
fields: {
state: { editable: false, type: "string", sort: "asc" },
fipsCode: { editable: false, type: "number", sort: "asc" },
year: { editable: false, type: "number", sort: "desc" },
name: { editable: false, type: "string" },
createdBy: { editable: false, type: "string" },
createdOn: { editable: false, type: "date" },
lastModifiedBy: { editable: false, type: "string" },
lastModifiedOn: { editable: false, type: "date" },
isEditable: { editable: false, type: "boolean" },
isReviewable: { editable: false, type: "boolean" }
}
}
}
},
groupable: false,
sortable: {
showIndexes: true,
mode: "multiple"
},
resizable: true,
selectable: "row",
scrollable: true,
filterable: true,
navigatable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 10
},
dataBound: this.GridDataBound,
columns: [
{
field: "submissionId",
title: "Id",
},
{
field: "state",
title: "State",
filterable: {
multi: true,
dataSource: this.BuildMultiCheckboxDataSource("state", "name", true)
},
sort: "ascending"
},
{
field: "year",
title: "Year",
filterable: {
multi: true,
dataSource: this.BuildMultiCheckboxDataSource("year", null, true)
},
sort: "descending"
},
{
field: "status",
title: "Status",
filterable: {
multi: true,
dataSource: this.BuildMultiCheckboxDataSource("status", null, true)
}
},
{
field: "createdBy",
title: "Initiated By",
filterable: {
ui: this.FormCreatedByAcceptedFilter
}
},
{
field: "createdOn",
title: "Initiated On",
format: "{0:g}",
},
{
field: "lastModifiedBy",
title: "Modified By",
filterable: {
ui: this.FormLastModifiedByAcceptedFilter
}
},
{
field: "lastModifiedOn",
title: "Modified On",
format: "{0:g}"
},
{
title: "Action",
headerTemplate: "<div class='headerTemplate'><span class='headerText'>Action</span>" +
"<button class='clearAllFilters' id='clearAllFiltersAcceptedSubmissions' tabindex=0> Clear All Filters</button></div>",
command: [
{
name: "View",
text: " ",
visible: function (dataItem) { return !dataItem.isEditable },
template: function () {
var tmpl = "<a role='button' class='k-button k-button-icontext k-grid-View' title='View Form' tabindex=0>" +
"<i aria-hidden='true' class='fa fas fa-eye'><span class='sr-only'>View form</span></i></a>";
return tmpl;
},
click: function (e) {
e.preventDefault();
var data = this.dataItem($(e.target).closest("tr"));
$("#submissionId").val(data.submissionId);
commonFormsModule.UpdateFormMetadata(data, "from-grid")
gridSubmissionStatusHistory.dataSource.read();
commonFormsModule.SwitchTo("view-existing-form", module);
}
},
{
name: "View History",
text: " ",
visible: function (dataItem) { return !dataItem.isReviewable },
template: function () {
var tmpl = "<a role='button' class='k-button k-button-icontext k-grid-ViewHistory' title='View Form History' tabindex=0>" +
"<i aria-hidden='true' class='fa fas fa-history'><span class='sr-only'>View form history</span></i></a> ";
return tmpl;
},
click: function (e) {
var data = this.dataItem($(e.target).closest("tr"));
$("#submissionId").val(data.submissionId);
commonFormsModule.UpdateFormMetadata(data, "from-grid")
gridSubmissionStatusHistory.dataSource.read();
commonFormsModule.SwitchTo("view-status-history", module);
}
}
],
},
]
}).data("kendoGrid");
gridAcceptedSubmissions.hideColumn(0);
$("#clearAllFiltersAcceptedSubmissions").click(function () {
gridAcceptedSubmissions.dataSource.filter({});
});
},
Without seeing what BuildMultiCheckboxDataSource is doing, I can only make assumptions.
However, since you have declared year as an IEnumerable<int> then the datasource does not need to be anything elaborate. Simply set it to the collection being returned by the server:
{
field: "year",
title: "Year",
filterable: {
multi: true,
dataSource: new kendo.data.DataSource({
transport: {
read: {
url: "/my-endpoint-to-fetch-years-here"
}
}
})
},
sort: "descending"
}
I am having problem getting the Kendo Grid to work correctly. I am using ASP.NET WebAPI to fetch data from SQL Server and display it in the grid. Use the Kendo Grid to do Updates and Deletes.
POST: While debugging I noticed that a NULL object in IE but Chrome gets a valid data.
which I am passing to update the DB.
IE versions 10 and 11. There are no JS errors but the object is NULL on the WEB API.
WEBAPI - GET Works (IE and Chrome),
POST/DELETE does not work in IE (Works in Chrome)
#model dynamic
#{
ViewBag.Title = "FunctionalGroup";
}
<div class=".col-xs-12 .col-sm-6 .col-lg-8">
<div class="well well-sm">
<h2>Functional Groups - Management</h2>
<p>Create, Update and Delete Functional Groups</p>
</div>
<div class="row">
<div class="well well-sm">
<div style="overflow-x: auto" id="FunctionalGroupGrid"></div>
<div id="window"></div>
</div>
</div>
<div>
<button data-role="button" data-icon="cancel"></button>
</div>
</div>
#section Scripts{
<script type="text/x-kendo-template" id="windowTemplate">
<p>Delete <strong>#= FunctionalGroupName #</strong> ? </p>
<p>#= FunctionalGroupDescription # </p>
<button class="k-button" id="yesButton">Yes</button>
<button class="k-button" id="noButton"> No</button>
</script>
<script>
var windowTemplate = kendo.template($("#windowTemplate").html());
var window = $("#window").kendoWindow({
title: "Are you sure you want to delete this record?",
visible: false, //the window will not appear before its .open method is called
modal: true,
resizable: false,
width: "400px",
height: "200px",
}).data("kendoWindow");
var LookupFunctionalGroupType = new kendo.data.DataSource({
transport: {
read: "/api/FunctionalGroupType",
datatype : "json"
}
});
function getfunctionalGroupType(functionalGroupTypeID) {
for (var idx = 0, length = LookupFunctionalGroupType.length; idx < length; idx++) {
if (LookupFunctionalGroupType[idx].FunctionalGroupTypeID === functionalGroupTypeID) {
return LookupFunctionalGroupType[idx].FunctionalGroupTypeName;
}
}
}
function functionalGroupTypeDropDownEditor(container, options) {
$('<input data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataTextField: "FunctionalGroupTypeName",
dataValueField: "FunctionalGroupTypeID",
dataSource: LookupFunctionalGroupType
}).appendTo(container);
}
$(function () {
var baseUrl = "/api/FunctionalGroup";
var datatype = "json";
var contentType = "application/json";
var datasourceFG = new kendo.data.DataSource({
serverPaging: true,
pageSize: 10,
autoSync: false,
batch: true,
transport: {
read: {
url: baseUrl,
dataType: datatype,
contentType: contentType
},
create: {
url: baseUrl,
dataType: datatype,
contentType: contentType,
type: "POST"
},
update: {
url: baseUrl,
dataType: datatype,
contentType: contentType,
type: "PUT"
},
destroy: {
url: baseUrl,
dataType: datatype,
contentType: contentType,
type: "DELETE"
}
, parameterMap: function (data, operation) {
if (operation !== "read" && data.models) {
return kendo.stringify(data.models);
}
else {
return {
take: data.take,
skip: data.skip,
pageSize: data.pageSize,
page:data.page
}
}
},
},
schema: {
data: "Data.$values",
total: "RecordCount",
model: {
id: "FunctionalGroupID",
fields: {
FunctionalGroupID: { editable: false, type: "number" },
FunctionalGroupName: { editable: true, nullable: false, validation: { required: true } },
FunctionalGroupDescription: { editable: true, nullable: false, validation: { required: true } },
FunctionalGroupTypeID: { field: "FunctionalGroupTypeID", type: "number", defaultValue: 101 },
IsActive: { editable: true, nullable: false, type: "boolean" },
CreatedBy: { editable: false, nullable: false, validation: { required: true } },
CreatedDateTime: { editable: false, type: "date", format: "{0:MM/dd/yyyy HH:mm:ss}" },
ModifiedBy: { editable: false},
ModifiedDateTime: { editable: false, type: "date", format: "{0:MM/dd/yyyy HH:mm:ss}" }
}
},
}
});
$("#FunctionalGroupGrid").kendoGrid({
dataSource: datasourceFG,
navigatable: true,
autoBind: false,
pageable: true,
resizable: true,
reorderable: true,
editable: kendo.support.mobileOS ? "popup":true,
groupable: true,
filterable: true,
sortable:true,
columnMenu: true,
selectable: "row",
mobile: true,
toolbar: ["create", "save", "cancel"],
columns: [
{ field: "FunctionalGroupID", width: 50, title: "ID", hidden: true },
{ field: "FunctionalGroupName", width: 150, title: "Functional Group" },
{ field: "FunctionalGroupDescription", width: 200, title: "Description" },
{
field: "FunctionalGroupTypeID", width: 180, title: "Functional Group Type"
, template: '#=getfunctionalGroupType(FunctionalGroupTypeID)#'
, editor: functionalGroupTypeDropDownEditor, filterable:false
},
{
field: "IsActive", width: 80, title: "Is Active",
template: '<input type="checkbox" #= IsActive ? checked="checked" : "" # disabled="disabled" ></input>'
},
{ field: "CreatedBy", width: 100, title: "Created By", hidden: true },
{ field: "CreatedDateTime", width: 100, title: "Created DateTime", format: "{0:MM/dd/yyyy}", hidden: true },
{ field: "ModifiedBy", width: 100, title: "ModifiedBy", hidden: true },
{ field: "ModifiedDateTime", width: 100, title: "Modified DateTime", format: "{0:MM/dd/yyyy}", hidden: true },
{
title: "Actions",
command: [
{
name: "destroy",
text: "Delete",
click: function (e) { //add a click event listener on the delete button
var tr = $(e.target).closest("tr"); //get the row for deletion
var data = this.dataItem(tr); //get the row data so it can be referred later
window.content(windowTemplate(data)); //send the row data object to the template and render it
window.open().center();
$("#yesButton").click(function () {
grid.dataSource.remove(data) //prepare a "destroy" request
//grid.dataSource.sync() //actually send the request (might be ommited if the autoSync option is enabled in the dataSource)
window.close();
})
$("#noButton").click(function () {
window.close();
})
}
}
]
}
]
});
LookupFunctionalGroupType.fetch(function () {
LookupFunctionalGroupType = this.data(); //First fetch the Lookup data
datasourceFG.read(); // This will bind to the grid.
});
});
</script>
Which versoin of IE are you running? Are you seeing JS error in IE?
I see in your secript
},
}
You might want to remove "," if there are no elements following it in the list
i create grid with data by javascript. when i click edit button at first time on any row and click update button. values in first row are null and then i edit other row i can't update or cancel, both button are not working.
when i refresh then click edit and then click cancel that row has removed i don't know why?
What's happend? How to fix?
Data
var detail = new Array();
for (var i = 1; i < 6; i++) {
detail.push({
Score: i,
Condition: 0,
ValueStart: 0,
ValueEnd: 0,
});
}
Grid
for (var i = 0; i < 3; i++) {
$("#GridScoreRangeContent").append("<div id='scoreRangeGrid_"+i+"'></div>");
$("#scoreRangeGrid_"+i).kendoGrid({
dataSource: {
data: detail,
batch: true,
schema: {
model: {
fields: {
Score: { editable: false },
Condition: { defaultValue: { Value: 1, Text: "Less than" }, validation: { required: true } },
ValueStart: { type: "number", validation: { required: true, min: 1 } },
ValueEnd: { type: "number", validation: { required: true, min: 1 } },
}
}
}
},
columns: [{ field: "Score", title: "Score" }},
{ field: "Condition", title: "Condition", editor: ScoreRangeDropDownList, template: "#=Condition#" },
{ field: "ValueStart", title: "Start" },
{ field: "ValueEnd", title: "End" },
{ command: ["edit", "destroy"], title: " ", width: "180px" }
],
editable: "inline"
});
}
Load Dropdownlist
function ScoreRangeDropDownList(container, options) {
$.ajax({
url: GetUrl("Admin/Appr/LoadDropdownlist"),
type: 'post',
dataType: 'json',
contentType: 'application/json',
traditional: true,
cache: false,
success: function (data) {
$('<input required data-text-field="Text" data-value-field="Value" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind: false,
dataSource: data,
dataTextField: "Text",
dataValueField: "Value",
});
}
});
}
Kendo seems to rely on a model ID when saving/updating. So in your dataSource, you have to specify an id:
model: {
id: "Id",
fields: {
Id: { type: "number" },
Score: { editable: false },
Condition: { defaultValue: { Value: 1, Text: "Less than" }, validation: { required: true } },
ValueStart: { type: "number", validation: { required: true, min: 1 } },
ValueEnd: { type: "number", validation: { required: true, min: 1 } },
}
}
What dmathisen is suggesting is definitely important but in addition it is important that the <input/> you create has a name attribute equal to the name of the column. You can use the value of options.field again as in the code from the Kendo Demos page example:
// create an input element
var input = $("<input/>");
// set its 'name' to the field to which the column is bound
input.attr("name", options.field);
// append it to the container
input.appendTo(container);
// initialize a Kendo UI Widget
input.kendoDropDownList({
.
.
I can able to filer the matched data using filter button.How to get the popup window if there is no matched data after clicking the filter data.Present If there is no matched data the table is showing empty instead of that how to rise a pop to tell no matched data to filter
// Set up information window
$("#filter-msg").kendoWindow({
modal: true,
visible: false
});
// Set up date pickers
$("#datetimepicker1").kendoDatePicker({});
$("#datetimepicker2").kendoDatePicker({});
// Set up DDL
var categories = $("#categories").kendoDropDownList({
optionLabel: "Select category...",
dataTextField: "CategoryName",
dataValueField: "CategoryID",
dataSource: {
type: "odata",
serverFiltering: true,
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Categories"
}
}
}).data("kendoDropDownList");
var products = $("#products").kendoDropDownList({
autoBind: false,
cascadeFrom: "categories",
optionLabel: "Select product...",
dataTextField: "ProductName",
dataValueField: "ProductID",
dataSource: {
type: "odata",
serverFiltering: true,
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Products"
}
}
}).data("kendoDropDownList");
var orders = $("#orders").kendoDropDownList({
autoBind: false,
cascadeFrom: "products",
optionLabel: "Select order...",
dataTextField: "Order.ShipCity",
dataValueField: "OrderID",
dataSource: {
type: "odata",
serverFiltering: true,
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Order_Details?$expand=Order"
}
}
}).data("kendoDropDownList");
// Bind "click" event on button "Filter"
$("#filter").on("click", function () {
var mindate = $('#datetimepicker1').data("kendoDatePicker").value();
var maxdate = $('#datetimepicker2').data("kendoDatePicker").value();
var product = $("#products").data("kendoDropDownList").value();
var order = $("#orders").data("kendoDropDownList").value();
if (!mindate || !maxdate || !product || !order) {
var content = "";
if (!mindate)
content += "<div class=\"k-error-colored\">mindate is not defined!</div>";
if (!maxdate)
content += "<div class=\"k-error-colored\">maxdate is not defined!</div>";
if (!product)
content += "<div class=\"k-error-colored\">product is not defined!</div>";
if (!order)
content += "<div class=\"k-error-colored\">order is not defined!</div>";
$("#filter-msg").data("kendoWindow")
.content(content)
.center()
.open();
return false;
}
var condition = {
logic: "and",
filters: [{
field: "OrderDate",
operator: "ge",
value: mindate
}, {
field: "OrderDate",
operator: "le",
value: maxdate
}]
};
grid.dataSource.filter(condition);
});
var grid = $("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Orders"
},
schema: {
model: {
fields: {
OrderID: {
type: "number"
},
Freight: {
type: "number"
},
ShipName: {
type: "string"
},
OrderDate: {
type: "date"
},
ShipCity: {
type: "string"
}
}
}
},
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
filterable: true,
sortable: true,
pageable: true,
columns: [{
field: "OrderID",
filterable: false
},
"Freight", {
field: "OrderDate",
title: "Order Date",
width: 100,
format: "{0:MM/dd/yyyy}"
}, {
field: "ShipName",
title: "Ship Name",
width: 200
}, {
field: "ShipCity",
title: "Ship City"
}]
}).data("kendoGrid");
Here is the js fiddle: http://jsfiddle.net/XHW3w/1/
Done, you can check using length property of dataSource.data
Here is the updated jsfiddle
grid.dataSource.filter(condition);
console.log(grid.dataSource.data.length);
if(grid.dataSource.data.length <= 1)
$("#filter-msg").data("kendoWindow")
.content("<div class=\"k-error-colored\">No record found!</div>")
.center()
.open();
Below is my grid.
If you look at the save: event, you'll notice an AJAX call.
This AJAX call IS firing, data IS being inserted into the database and I can even see the alert function going through. However, the grid does not exit edit mode for the row I'm inline editing. I'm not sure what's going on because the error message is terrible. I keep getting:
TypeError: Cannot read property 'data' of undefined [http://localhost/x/Scripts/kendo.web.min.js:13]
Here's the grid:
function directorsOrRecipients(e)
{
awardTitleId = e.data.AwardTitleId;
var detailRow = e.detailRow;
detailRow.find(".childTabstrip").kendoTabStrip({
animation: {
open: { effects: "fadeIn" }
}
});
detailRow.find(".directorsOrRecipients").kendoGrid({
reorderable: true,
resizable: true,
dataSource: {
transport: {
read: {
url: "http://localhost/x/api/Awards/directors/" + awardTitleId,
type: "GET"
},
},
schema: {
model: {
id: "AwardDirectorId",
fields: {
"AwardDirectorId": { editable: false, type: "number" },
"namefirstlast": { editable: true, type: "string" },
"directorsequence": { editable: true, type: "number", validation: { min: 1 } },
"isonballot": { editable: true, type: "string" },
"concatenation": { editable: true, type: "string" },
"MoreNames": { editable: true, type: "number", validation: { min: 0 } },
}
}
}
},
columns: [
{ field: "AwardDirectorId", title: "Award Director Id" },
{ field: "namefirstlast", title: "Name", editor: namesAutoComplete },
{ field: "directorsequence", title: "Director Sequence", format: "{0:n0}" },
{ field: "isonballot", title: "On ballot?", editor: onBallotDropDownEditor },
{ field: "concatenation", title: "Concatenation" },
{ field: "MoreNames", title: "More names?", format: "{0:n0}" },
{ command: ["edit"], title: " ", width: 100 }],
sortable: true,
sort: { field: "namefirstlast", dir: "desc" },
editable: "inline",
toolbar: [{ name: "create", text: "Add New Director/Recipient" }],
save: function(e)
{
debugger;
if (e.data != "undefined")
{
$.ajax({
url: "http://localhost/x/api/awards/directors",
type: "POST",
dataType: "json",
data: $.parseJSON(directorData)
}).done(function()
{
alert('done!');
});
}
}
});
function onBallotDropDownEditor(container, options)
{
var data = [
{ "onBallotId": 1, "onBallotDescription": "Yes" },
{ "onBallotId": 2, "onBallotDescription": "No" }];
$('<input required data-text-field="onBallotDescription" data-value-field="onBallotDescription" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind: false,
dataSource: data
});
}
}
After Success in Ajax call try this,
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
In controller update function return an object insted of empty Json, like this it worked for me
return Json(ModelState.IsValid ? new object() : ModelState.ToDataSourceResult());