Kendo UI Grid returns JSON to browser (using MVC) - ajax

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

Related

Kendo DataSource requestEnd event gets fired multiple times

I am using Telerik UI for ASP.NET MVC and i have grid defined as below
#(Html.Kendo().Grid<GridModel>()
.Name("grid")
.Columns(col =>
{
col.Bound(o => o.ID)
.ClientTemplate("<input class = 't-checkbox-selectrow' type='checkbox' value='#=ID#'/><label></label>")
.HeaderTemplate("<input class = 't-checkbox-selectallrows' type='checkbox' id='selectAll'/><label></label>")
.Sortable(false)
.Filterable(false)
.HtmlAttributes(new { #class = "t-gridcol-selectrow" })
.Width(40)
.Locked(true).Lockable(false);
col.Bound(o => o.StatusName).Width(150);
col.Bound(o => o.Deadline).Width(120);
col.Bound(o => o.Cost).Width(150);
})
.AutoBind(false)
.Pageable(x => x.PageSizes(UIConstants.PageSizes))
.Sortable(x => x.AllowUnsort(false))
.Resizable(resizing => resizing.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Scrollable(s => s.Height("Auto"))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(UIConstants.DefaultPageSizeMax)
.Read(read => read
.Action("GetData", "DataProvider"))
.ServerOperation(false))
)
Then in the JS file i am resetting the grid's page to 1 onRequestEnd, So user always goes back to first page whenever i fetch the data from remote service
$(function(){
var ds = $("#grid").data("kendoGrid").dataSource;
ds.bind("requestEnd", function (e){
e.sender.page(1);
})
})
As per the kendo's documentation
requestEnd
Fired when a remote service request is finished.
However the requestEnd event also gets fire on page change (and sorting). So when i change the page programmatic it fires the requestEnd event again and goes into loop. ( note requestEnd also gets fired when i change Page or Sort manually on UI)
Is this is by design or wrong documentation?
i did something like below. e.response will be only populated when requestEnds as part of response from server. In all other cases it will null.
dataSource.bind("requestEnd", function (e) {
if (e.status != "error" && e.response != null) {
// do soemething here
}
I would really like kendo team either fix the issue or create new event
This question was asked 3 years ago, but I am coming across it while looking up some other information. While I am here, I will answer it for others, as LP13 is likely not concerned about this anymore.
In the HTML Razer code, add the RequestEnd event to the DataSource. Here is an example:
#(Html.Kendo().Grid<GridModel>()
.Name("grid")
// (snip)
.DataSource(dataSource => dataSource
.Ajax()
.Events(o => o.DataBound("onDataBound"))
.PageSize(UIConstants.DefaultPageSizeMax)
.Read(read => read
.Action("GetData", "DataProvider"))
.ServerOperation(false))
)
Now in your jquery, you would write your event handler:
function onRequestEnd(e) {
console.log('onRequestEnd: e.response Object(The raw remote service response) = ', e.response);
console.log('onRequestEnd: e.sender kendo.data.DataSource(The data source instance which fired the event) = ', e.sender);
console.log('onRequestEnd: e.type String (The type of the request) = ', e.type);
}

Kendo UI Grid data is always empty at client-side, when binding it from server side

I am binding Kendo Grid from ASP.NET MVC as follows:
#(Html.Kendo().Grid<My.Web.Models.Generated.CustomerSearch01.CityInfo>()
.Name("gridCities")
.Columns(columns =>
{
columns.Bound(c => c.Text).Width(140).Title("City");
})
.Scrollable()
.Selectable(selectable => selectable.Type(GridSelectionType.Row))
.BindTo(Model.CitiesList)
.DataSource(ds => ds.Server().Model(m => m.Id(p => p.Value)))
)
That works fine and the grid shows up on the page with data and I have no problems with above. However, using browser developer tools, if I try to get the data of the above grid using the following statement, it returns empty:
jQuery("#gridCities").data("kendoGrid").dataSource.data()
What am I missing?
Thanks in advance
Solution (based the answer):
replace the following:
.DataSource(ds => ds.Server().Model(m => m.Id(p => p.Value)))
with
.DataSource(ds => ds.Ajax().ServerOperation(false).Model(m => m.Id(p => p.Value)))
You Grid is configured to use ServerBinding which means the TR / TD elements are rendered from the server. If you want to have the JavaScript objects of your model on the client side and do not perform separate Ajax request configure your DataSource to be
ds.Ajax().ServerOperations(false)
This will not perform any Ajax requests, data will be serialized from the server int JSON.

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

How to determine if there were validation errors after calling (Kendo) grid.SaveChanges() in javascript

I call grid.SaveChanges() in my javascript function. The grid is using inline editing mode.
My problem is if there were some client side validation errors for example invalid date format, then I must not execute some DOM operations. Unfortunately grid.SaveChanges() has no return value and searching for keyword 'valid' in grid documentation page has no result. (Teleport to Kendo Grid API documentation)
So: How can I determine if there was validation errors after SaveChanges() or the data was successfully sync-ed with the persistent store?
Thx in advance
I'm assuming that you are using the MVC wrappers but calling grid.SaveChanges() as part of your script. Since you're using inline editing mode, that means you're using Ajax. If those assumptions are correct, then when you call SaveChanges() your controller action specified in the wrapper is executed. If you hook into the .Error event you can execute whatever script needs to be executed (even if that's just setting a variable that you check in the other parts of your script). Have a look at the Ajax Editing portion of Getting Started on Kendo's website. Your Razor code will look similar to the following (some of this is extraneous, I pulled it out of production code and modified slightly):
#(Html.Kendo().Grid(Model)
.Name("Grid")
.Columns(cols =>
{
cols.Bound(p => p.ColumnA);
})
.Editable(edit => edit.Enabled(true).Mode(GridEditMode.InCell))
.DataSource(ds => ds
.Ajax()
.AutoSync(false)
.Model(model =>
{
model.Id(p => p.ColumnId);
})
// Configure RU -->
.Read(read => read.Action("_MyRead", "MyController").Data("additionalData"))
.Update(update => update.Action("_MyUpdate", "MyController").Data("additionalData"))
//.ServerOperation(false)
.Batch(true)
.Events(events => events
.Error("onError")
)
)
// <-- Configure RU
.Pageable(page => page.PageSizes(new int[] { 10, 25, 50, 100 }).Enabled(true))
.Groupable(group => group.Enabled(true))
.Filterable(filter => filter.Enabled(true).Extra(false))
.Sortable(sort => sort.Enabled(true).SortMode(GridSortMode.SingleColumn).AllowUnsort(true))
.Navigatable(nav => nav.Enabled(true))
.Resizable(resizing => resizing.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
)
Then your onError script will look like this:
function onError(e, status) {
if (e.errors) {
var message = "The following errors have occurred and changes will be discarded:\n";
$.each(e.errors, function (key, value) {
if (value.errors) {
message += value.errors.join("\n");
}
});
alert(message);
var grid = $("#Grid").data("kendoGrid");
grid.cancelChanges();
}
}

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