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
Related
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!
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().
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);
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");
})
)
I am working on asp.net mvc. I am trying to display list of messages in a Kendo mvc ui grid.
I have written the code like,
Html.Kendo().Grid((List<messages>)ViewBag.Messages))
.Name("grdIndox")
.Sortable(m => m.Enabled(true).SortMode(GridSortMode.MultipleColumn))
.HtmlAttributes(new { style = "" })
.Columns(
col =>
{
col.Bound(o => o.RecNo).HtmlAttributes(new { style = "display:none" }).Title("").HeaderHtmlAttributes(new { style = "display:none" });
col.Bound(o => o.NoteDate).Title("Date").Format("{0:MMM d, yyyy}");
col.Bound(o => o.PatName).Title("Patient");
col.Bound(o => o.NoteType).Title("Type");
col.Bound(o => o.Subject);
}
)
.Pageable()
.Selectable(sel => sel.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row))
.DataSource(
ds => ds.Ajax().ServerOperation(false).Model(m => m.Id(modelid => modelid.RecNo))
.PageSize(10)
//.Read(read => read.Action("Messages_Read", "Msg"))
)
.Events(ev => ev.Change("onSelectingGirdRow"))
)
and i have the field in the table like IsRead-boolean type. so if the message is unread message then i need to format that record with bold font. I have used clientTemplates but with that i am able to format only particular cells i want format entire row. Please guide me.
as Sanja suggested you can use the dataBound event but it will be better to cycle through the tr elements (the rows). Also I assume that you will need the related dataItem to check if the property that indicates if the message is read.
e.g.
dataBound: function ()
{
var grid = this;
grid.tbody.find('>tr').each(function(){
var dataItem = grid.dataItem(this);
if(!dataItem.IsMessageRead)
{
$(this).addClass('someBoldClass');
}
})
}
You can use dataBound event to change your rows.
dataBound: function ()
{
$('td').each(function(){
if(some condition...)
{
$(this).addClass('someBoldClass')}
}
})
}
There is another way to do that.It's called RowAction.
.RowAction(row =>
{
if (condition)
{
row.HtmlAttributes["class"] = "someBoldClass";
}
})
Please note that the RowAction is available only for rows that are rendered on server side. So in your case, you can use RowAction as an alternative to DataBound.