Telerik MVC Grid Inline editing requires page refresh to display changes - asp.net-mvc

I have a Telerik MVC Grid where I am updating the rows inline (updating name column, number column is uneditable)
#Html.Kendo().Grid(Model.Employees)
.Name("EmployeeGrid")
.Columns(col =>
{
col.Bound(o => o.EmployeeNumber);
col.Bound(o => o.Name).Width(250);
col.Command(command => { command.Edit(); });
})
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Events(e => e.RequestEnd("onGridDataSourceRequestEnd"))
.Model(model =>
{
model.Id(o => o.EmployeeNumber);
model.Field(o => o.EmployeeNumber).Editable(false);
})
.Update(update => update.Action("EditingInline_Update", "EmployeeUpdate"))
.ServerOperation(false)
)
.Render();
function onGridDataSourceRequestEnd(e) {
if (e.type == "update") {
console.log('I am inside Update');
$("#EmployeeGrid").data("kendoGrid").dataSource.read();
}
}
My problem is that above code updates the record by calling action EmployeeUpdate when I click on Update button in the grid. However, that change doesnt immediately reflect in the grid even though I am calling datasource read in JS function. Console shows "I am inside Update" but doesnt refresh grid. If I refresh the page, I do see the update row.
Please let me know what am I missing. Thank you.

You should not have to refresh/reload your grid when doing an update, you just have to return the updated record from the controller and grid-widget will take care of the rest!
Please checkout telerik demo-page
The most common error I do is forgetting to return a datasourceresult:
.ToDataSourceResult(request,ModelState)
Telerik normally returns the same model that are sent in to the update, but I normally returns the same object that the read function returns (if read does something I'll get that on the updated record too).

Probably you should try refreshing the grid with refresh() function:
function onGridDataSourceRequestEnd(e) {
if (e.type == "update") {
console.log('I am inside Update');
$("#EmployeeGrid").data("kendoGrid").dataSource.read();
// add this line
$("#EmployeeGrid").data("kendoGrid").refresh();
}
}
Note that read() function in dataSource only reload data source by request to the server, the grid contents still not changed before using refresh().

Related

Kendo MVC TreeList not Rendering from Initial BindTo

My MVC ViewModel contains the initial list of records to be displayed within my Kendo TreeList. However, the TreeList is NOT rendering the initial list...and I don't understand why.
REQUIREMENTS:
If initial records exist...display them
The READ ACTION CANNOT be executed on the initial render (other controls manage that later)
For other Kendo controls, you set:
AutoBind(false)
BindTo(Model.MyCollectiom)
...and the READ ACTION does not execute. But the TreeList is failing at the moment.
MY RAZOR LOOKS LIKE:
At initial render records DO EXIST (see image below)
#(Html.Kendo().TreeList<DeviceHierarchyDataItem>()
.Name("treeTarget")
.Columns(columns =>
{
columns.Add().Field(e => e.DisplayName)
.TemplateId("tmplDisplayName")
.Title(" ");
})
.BindTo(Model.TargetDevices)
.AutoBind(false)
.DataSource(dataSource => dataSource
.Read(read => read.Action("find", "devicehierarchy", new { Area = "" })
.Data("window.etp.pageController.getFilter"))
.ServerOperation(false)
.Model(m =>
{
m.Id(f => f.Id);
m.ParentId(f => f.ChildOf);
m.Expanded(true);
m.Field(f => f.DisplayName);
}))
.Sortable())
Strangely enough the TreeList MVC control doesn't support binding to local data...
At least not in july 2018...
The recommendation is to use the jquery control instead.
And then convert the data from the Model to a json string:
$(document).ready(function () {
var dataSource = new kendo.data.TreeListDataSource({
data: #Html.Raw(Json.Encode(#Model.TargetDevices)),
schema: {
model: {
id: "Id",
parentid: "ChildOf",
expanded: true
}
}
});
I hope it helps!

Dropdown list in ASP MVC Kendo grid will not open

I am trying to replicate exactly what is on this Kendo demo page with the Categories column. Simply a drop down list inside the grid. I copied all their source code exactly, but when I click the column with a drop down, the grid simply flashes. I can edit the FullName value fine. I tried to get an animation of the effect with a screen recorder, but for some reason it is not showing everything I see. In this image I am clicking the "Rol" drop down column multiple times.
What the gif does not show is that when I click the column, it briefly changes to a drop down control for a split second. I was able to capture this by adding a "debugger" line to the onDataBound event for the dropdown and taking a screenshot:
What is going on? Why doesn't it just pop open?
Here is some of the relevant code:
The EditorTemplates/RolList.cshtml file. Note that NONE of these events fire except the onDataBound event. That is probably a clue.
#model MyCompany.Web.CaseLink.Mvc.Admin.Models.RolDropDown
#(Html.Kendo().DropDownListFor(m => m)
.BindTo((System.Collections.IEnumerable)ViewData["roles"])
.DataValueField("RolId")
.DataTextField("RolDescription")
.Events(events => events
.Select("onSelect")
.Change("ddlChange")
.Open("onOpen")
.DataBound("onDatabound")
)
)
<script type="text/javascript">
function onSelect(e) {
console.log("ddl select" + e);
}
function ddlChange(e) {
console.log("ddl change" + e);
}
function onOpen(e) {
console.log("ddl open" + e);
}
function onDatabound(e) {
debugger;
console.log("ddl databound" + e);
}
</script>
Here is the partial view containing the MVC Grid itself. Note that the gridChange event was added just for debugging, and it does not fire when clicking in the drop down column.
#(Html.Kendo().Grid<CaseMemberGridRow>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.FullName)
.Title("Name")
;
columns.Bound(p => p.Rol).ClientTemplate("#=Rol.RolDescription#").Width(180);
columns.Bound(c => c.Email)
.Title("Email")
;
columns.Bound(c => c.Telephone)
.Title("Phone")
;
columns.Command(command => command.Destroy()).Width(150);
})
.ToolBar(toolBar =>
{
toolBar.Create();
toolBar.Save();
})
.HtmlAttributes(new { style = "height: 550px;" })
.Scrollable()
.Sortable()
.Editable(editable => editable.Mode(GridEditMode.InCell))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.ServerOperation(false)
.Events(events => events.Error("error_handler").Change("gridChange"))
.Model(m =>
{
m.Field(p => p.FullName).Editable(true);
m.Field(p => p.Rol).Editable(true);
m.Field(p => p.Rol).DefaultValue(
ViewData["defaultRol"] as MyCompany.Web.CaseLink.Mvc.Admin.Models.RolDropDown);
})
.Create(create => create.Action("AddCaseMemberNoCustomerRecord_Create", "AddMember"))
.Update(update => update.Action("AddCaseMemberNoCustomerRecord_Update", "AddMember"))
)
)
Controller is nothing special, as I said, I am doing exactly when Telerik did in their demo. A sample:
var roles = _rolService.GetAllRolesDTO()
.OrderBy(o => o.Description)
.Select(r => new RolDropDown
{
RolDescription = r.Description,
RolId = r.RolId
});
ViewData["roles"] = roles;
ViewData["defaultRol"] = roles.First();
If there is something to look for in the debugger on the "onDataBound" event, let me know. As you can see here, the datasource is definitely populated.
EDIT: I am aware that you can attempt to do the same thing using the ForeignKey type of column. When I try that, I can get a drop down to work once. After selecting a value, the column starts acting like before where you cannot change the value.
columns.ForeignKey(p => p.RolId, (System.Collections.IEnumerable)ViewData["roles"], "RolId", "Description")
.Title("Role")
.Width(150);

Kendo UI Chart - Updating datasource after databound

I have some actions that need to be executed during/after databinding of my charts.
One of the things is that I'm adding missing categories (months). My problem is that if I add those missing values to the datasource, it triggers the databound event again.
Is there a better way to do this?
#(Html.Kendo().Chart<MyModel>()
.Name("chart")
.DataSource(ds => ds.Read(read => read.Action("GetData", "Home")))
.CategoryAxis(a => a.Date().Categories(c => c.Date))
.ValueAxis(v => v.Numeric().Min(0).Max(100))
.Series(series => series.Column(d => d.Value))
.Events(e => e.DataBound("dataBound"))
)
function dataBound(e) {
var chart = e.sender;
var today = new Date();
// Add current month to chart
chart.dataSource.add({
CategoryDate: today,
Value: 0
});
}
Every time data inside DataSource is added, modified or deleted DataSource will trigger event Change, and every widget which has DataSource will trigger event DataBound after DataSource is changed.
Therefore your DataBound event is triggered twice, whereas your chart using remote service to Read its data, internally there are 2 events which will be trigger to achieve it. Event RequestStart and RequestEnd will be called, so I suggest you add your missing category inside the datasource RequestEnd event.
Inside the RequestEnd event you can modify its response data, you could debug it to see the full structure of this response; normally it will have the Data property and this is the property that you need to change.
Sample Code
#(Html.Kendo().Chart<MyModel>()
.Name("chart")
.DataSource(ds => ds.Read(read => read.Action("GetData", "Home"))
.Events(evt => evt.RequestEnd("onChartDsRequestEnd")))
.CategoryAxis(a => a.Date().Categories(c => c.Date))
.ValueAxis(v => v.Numeric().Min(0).Max(100))
.Series(series => series.Column(d => d.Value))
.Events(e => e.DataBound("dataBound"))
)
function onChartDsRequestEnd(e) {
// data you should modify before its being placed as datasource's data
var responseData = e.response;
responseData.push({.......});
}
Datasource RequestEnd Documentation

Kendo UI MVC inline client-side grid - clicking cancel removes row. Not the model ID issue

I have a Kendo grid set up for client-side only. Whenever I add a row, then edit it, then cancel - it gets removed. Multiple questions have been asked here and on the Kendo forums about this same issue, and all the suggestions point to incorrect setup of the model's ID.
Well, in my case the ID seems to be set up correctly. I am assigning a new ID to the model in the onGridSave() javascript event, like this:
var _curId = 1;
function onGridSave(e) {
var newId = _curId++;
e.model.set('id', newId);
e.model.set('EncryptedIngredientId', newId);
}
And when I look at the data in the grid after having added multiple rows, all of their IDs are unique - from 1 to n.
But when I cancel an edit, in the onGridChange() event the action is "remove", and the cancelled row is removed. This happens for new rows as well as for edited rows, while it should only be the case for new rows.
The grid is set up as follows:
#(Html.Kendo().Grid<IngredientViewModel>(Model.ServerData)
.Name("IngredientsGrid")
.Editable(editable => editable.Mode(GridEditMode.InLine).Enabled(true))
.BindTo(Model.DataAfterEdit ?? Model.ServerData)
.DataSource(ds => ds
.Ajax()
.ServerOperation(false)
.Events(ev => ev.Change("onGridChange").Error("onGridError"))
.Model(m => {
m.Id(p => p.EncryptedIngredientId);
m.Field(p => p.EncryptedIngredientId).DefaultValue(Guid.NewGuid().ToString());
m.Field(p => p.PercentInfo).DefaultValue(new PercentInfoViewModel());
})
.Read("IngGrid_Read", "Company") // <-- dummy action that doesn't exist in controller
.Update("IngGrid_Update", "Company") // <-- dummy action that doesn't exist in controller
.Create("IngGrid_Create", "Company") // <-- dummy action that doesn't exist in controller
.Destroy("IngGrid_Destroy", "Company")) // <-- dummy action that doesn't exist in controller
.ToolBar(tbar => tbar.Create())
.Columns(c => {
c.AutoGenerate(false);
c.Bound(m => m.CasNumber);
c.Bound(m => m.IngredientName);
c.Bound(m => m.PercentInfo).ClientTemplate("#= makePercentageDisplayString(data.PercentInfo) #").Width(180);
c.Bound(m => m.ReachRegNumber);
c.Bound(m => m.ReachSvhc);
c.Bound(m => m.RohsSubstance);
c.Bound(m => m.Prop65Substance);
c.Command(command => {
command.Edit();
command.Destroy();
}).Width(200);
})
.Events(evt => {
evt.Save("onGridSave");
evt.Edit("onGridEdit");
})
)
What am I doing wrong?
When you declare this dummy actions, Kendo is trying to save data after you edit your cell. It perform create action but doesn't have correct response from the server so it believe that request was fail. Because of that it trying to remove row after you click cancel, cuz it can't find it in their dataSource.
If it gonna be just local grid as you said, the solution is add .Batch(true) on you grid dataSource config to prevent update action after you change cell.
If you wanna save your edited data on the server you should implement Update, Create and Destroy action correctly.
I also asked my question here:
http://www.telerik.com/forums/mvc---inline-client-side-grid---clicking-cancel-removes-row-probably-not-the-model-id-issue-#qn5VWKCX9kmpZnLuTzDveQ
It turns out this is not supported when using MVC wrappers, however it could be done using JavaScript. Since I didn't want to lose the type safety of C#, I implemented the CRUD actions on the controller and store rows in the session.
The only 2 things I had to change in my grid definition were: set .ServerOperation(true) instead of false; and remove the .BindTo(...) call. Resulting code looks like this:
#(Html.Kendo().Grid<IngredientViewModel>(Model.ServerData)
.Name("IngredientsGrid")
.Editable(editable => editable.Mode(GridEditMode.InLine).Enabled(true))
.DataSource(ds => ds
.Ajax()
.ServerOperation(true)
.Events(ev => ev.Change("onGridChange").Error("onGridError"))
.Model(m => {
m.Id(p => p.EncryptedIngredientId);
m.Field(p => p.EncryptedIngredientId).DefaultValue(Guid.NewGuid().ToString());
m.Field(p => p.PercentInfo).DefaultValue(new PercentInfoViewModel());
})
.Read("IngGrid_Read", "Company") // <-- dummy action that doesn't exist in controller
.Update("IngGrid_Update", "Company") // <-- dummy action that doesn't exist in controller
.Create("IngGrid_Create", "Company") // <-- dummy action that doesn't exist in controller
.Destroy("IngGrid_Destroy", "Company")) // <-- dummy action that doesn't exist in controller
.ToolBar(tbar => tbar.Create())
.Columns(c => {
c.AutoGenerate(false);
c.Bound(m => m.CasNumber);
c.Bound(m => m.IngredientName);
c.Bound(m => m.PercentInfo).ClientTemplate("#= makePercentageDisplayString(data.PercentInfo) #").Width(180);
c.Bound(m => m.ReachRegNumber);
c.Bound(m => m.ReachSvhc);
c.Bound(m => m.RohsSubstance);
c.Bound(m => m.Prop65Substance);
c.Command(command => {
command.Edit();
command.Destroy();
}).Width(200);
})
.Events(evt => {
evt.Save("onGridSave");
evt.Edit("onGridEdit");
})
)

Changing row color in Kendo MVC grid, using RowAction

I'm hoping to use RowAction with a lambda to set the background color of a few rows of data in a Grid.
<%: Html.Kendo().Grid<HomeController.SuccessfulBuildsByDevice>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.A);
columns.Bound(p => p.B);
})
.Scrollable()
.Sortable()
.Filterable()
.RowAction(row =>
{
if(row.DataItem.A > row.DataItem.B)
row.HtmlAttributes["style"] = "background:red";
})
.HtmlAttributes(new { style = "height:500" })
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("_GetData", "Home"))
.ServerOperation(false)
)
%>
However, when I use the above the RowAction() doesnt seem to be called. I tried setting a breakpoint, etc. Am I missing something in the intended use of RowAction(), does anyone see an obvious problem?
the problem is .Ajax() and .RowAction() are mutually exclusive
http://www.kendoui.com/forums/kendo-ui-web/grid/ajax-binding-and-rowaction-conflict-.aspx
Just because I came accorss this issue today and to save time here the short answer that worked for me based on the explanation from stuck
add this to the grid
.Events(e => e.DataBound("onDataBound"))
add this javascript above the grid
function onDataBound() {
// get the grid
var grid = this;
// iterate through each row
grid.tbody.find('>tr').each(function () {
// get the row item
var dataItem = grid.dataItem(this);
// check for the condition
if (dataItem.IsArchived) {
// add the formatting if condition is met
$(this).addClass('bgRed');
}
})
}

Resources