I am updating a grid cell with a date value on a button click from a custom command in the row (see code below). I am able to successfully add the value to the cell but I would like to have the cell show the red triangle in the upper left corner (see attached pic) that shows the user the value in the cell has been edited.
function
activate_deactivate(e) {
e.preventDefault();
var
tr = $(e.target).closest(
"tr"
);
//get the row
var
dataItem =
this
.dataItem($(e.currentTarget).closest(
"tr"
));
var
data =
this
.dataItem(tr);
//get the row data so it can be referred later
var
ad = dataItem.ActivatedOn;
if
(isDateActive(dataItem.ActivatedOn, dataItem.DeactivatedOn) || !dataItem.DeactivatedOn)
{
//set the deactivated date
var
strTodaysDate = getShortDate();
data.set(
"DeactivatedOn"
, strTodaysDate);
}
else
{
//clear the deactivated date (Now Active)
data.set(
"DeactivatedOn"
,
null
);
}
}
7 Answers, 1 is accepted
You can either manually add the dirty indicator the edited cell (by appending the span element used for the indicator) or call the following method after changing the value:
var grid = $("#grid").data("kendoGrid");
grid._modelChange({field:"ProductName", model: grid.dataSource.view()[0]}) //grid.dataSource.view()[0] should be replaced with the model you are editing
On a side note, please have in mind that the correct way of changing values is through the set method of the model: dataItem.set("fieldName", value);
Hope this helps.
Regards,
Konstantin Dikov
Telerik by Progress
I am using the data.set method in my code (see below) but the dirty flag is not being displayed. Do I need to do more to show the dirty flag?
function
activate_deactivate(e) {
e.preventDefault();
var
tr = $(e.target).closest(
"tr"
);
//get the row
var
dataItem =
this
.dataItem($(e.currentTarget).closest(
"tr"
));
var
data =
this
.dataItem(tr);
//get the row data so it can be referred later
var
ad = dataItem.ActivatedOn;
if
(isDateActive(dataItem.ActivatedOn, dataItem.DeactivatedOn) || !dataItem.DeactivatedOn)
{
//set the deactivated date
var
strTodaysDate = getShortDate();
data.set(
"DeactivatedOn"
, strTodaysDate);
}
else
{
//clear the deactivated date (Now Active)
data.set(
"DeactivatedOn"
,
null
);
}
}
The set method should be used in combination with manually appending the span element for the dirty flag to the cell:
<
span
class
=
'k-dirty'
></
span
>
You can refer to the following example for manually adding a dirty flag (although it is a different requirement, you can have it as a reference):
However, using the private _modelChange method should handle the changing of the value and the appending of the dirty flag, so I would suggest that you test that approach first and see if everything will work as expected with it.
Regards,
Konstantin Dikov
Telerik by Progress
Konstantin,
I was able to get an editable, sortable drop down for the ticket that we had discussed recently. (I ended up finding some time to delve further.)
I found this link:
http://jsbin.com/itevab/2/edit?html,js,output
very helpful in constructing the solution.
I came across that link from this link:
https://www.telerik.com/forums/kendo-grid---sort-on-column-bound-to-an-object
I was also able to get the dirty flag to appear using the manual append suggestion and the link you had provided
(https://docs.telerik.com/kendo-ui/controls/data-management/grid/how-to/Editing/preserve-the-dirty-indicator-in-incell-editing-and-client-operations?_ga=2.109639621.1731990048.1517769467-579472094.1515537534)
Thank you for that!
Just for a deeper understanding and to explore another option, I was wondering if you could clarify the _modelChange option. I don't understand what how to replace "grid.dataSource.view()[0]" with the model that I am editing.
I included my attempt do so within my update function (which appears within my editor template file):
@model object
<
script
type
=
"text/javascript"
>
function parentChange(e) {
$("#childGrid").data("kendoGrid").dataItem(this.element.closest("tr")).set("ParentDropDown", this.dataItem().ToJson());
//var grid = $("#childGrid").data("kendoGrid");
//grid._modelChange({ field: "ParentDropDown", model: grid.dataSource.view()[0]});
if (e.action == "itemChange") {
e.items[0].dirtyFields = e.items[0].dirtyFields || {};
e.items[0].dirtyFields[e.field] = true;
}
}
</
script
>
@(Html.Kendo().DropDownListFor(m => m)
.Name("ParentDropDown")
.Events(c => c.Change("parentChange"))
.DataValueField("ParentID")
.DataTextField("ParentName")
.DataSource(dataSource => dataSource
.Read(read =>
{
read.Action("ParentDropDownRead", "MultiBillTo");
})
.ServerFiltering(true)
)
)
Here is my grid with the javascript function for adding the dirty edit flag.
<
script
type
=
"text/javascript"
>
function dirtyField(data, fieldName) {
if (data.dirty && data.dirtyFields[fieldName]) {
return "<
span
class
=
'k-dirty'
></
span
>";
}
else {
return "";
}
}
</
script
>
@(Html.Kendo().Grid<
LDM.WebUI.Areas.Pricing.Models.MultiBillToChildViewModel
>()
.Name("childGrid")
.Columns(columns =>
{
columns.Bound(c => c.ParentDropDown.ParentName)
//.HtmlAttributes(new { @class = "templateCell" })
.ClientTemplate("#=dirtyField(data, 'ParentDropDown')# #=ParentDropDown.ParentName#")
.EditorTemplateName("ParentDropDown")
.Title("Parent")
.Width(350);
//columns.ForeignKey(c => c.ParentID, (System.Collections.IEnumerable) ViewData["parentDropDowns"], "ParentID", "ParentName").EditorTemplateName("ParentDropDown");
//columns.Bound(c => c.ParentDropDownName).Title("Parent").Width(350);
columns.Bound(c => c.ParentDropDown.ParentName).Title("ParentSortable").Width(350);
columns.Bound(c => c.CustomerID).Width(100);
columns.Bound(c => c.CustomerName).Width(350);
columns.Bound(c => c.ChildNotes).Width(500);
})
.DataSource(dataSource => dataSource
.Ajax()
.Batch(false)
.ServerOperation(false)
.Model(model =>
{
model.Id(c => c.RowID);
//model.Field(c => c.ParentDropDown).DefaultValue(ViewData["defaultDropDown"]);
//model.Field(c => c.ParentID).DefaultValue(ViewData["defaultDropDown"]);
model.Field(c => c.ParentDropDown).DefaultValue(ViewData["defaultDropDown"]);
model.Field(c => c.ParentDropDown).Editable(true);
})
.PageSize(50)
.Create(create => create.Action("MultiBillToChildrenCreate", "MultiBillTo"))
.Read(read => read.Action("MultiBillToChildrenRead", "MultiBillTo"))
.Update(update => update.Action("MultiBillToChildrenUpdate", "MultiBillTo"))
.Destroy(destroy => destroy.Action("MultiBillToChildrenDelete", "MultiBillTo"))
.Sort(sort =>
{
//sort.Add(c => c.ParentDropDown.ParentName);
sort.Add(c => c.ParentDropDown.ParentName);
}
)
)
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Excel(excel => excel
.FileName("MultiBillToChildren.xlsx")
.ProxyURL(Url.Action("ExcelExportSave", "MultiBillTo"))
)
.Filterable()
.HtmlAttributes(new { style = "height:600px;" })
.Pageable()
.Scrollable()
.Sortable(s => s.AllowUnsort(false))
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Save();
toolbar.Excel();
}
)
)
I commented out my attempt to use _modelChange after I could not get it to work and switched to the manual append method.
Could you please provide additional detail on the _modelChange option?
Thank you,
Matt Pugsley
With the latest version you could use the "set" method and it will add the dirty indicator internally:
As for the currently edited dataItem, this is the line that get reference to the item:
var currentItem = $("#childGrid").data("kendoGrid").dataItem(this.element.closest("tr"));
Nevertheless, since the _modelChange is a private method I would not recommend using it, because it could change over time and it is not part of the public API where we are trying to avoid breaking changes.
Hope this helps.
Regards,
Konstantin Dikov
Progress Telerik
Konstantin,
I think I understand. Can you please confirm the below?
1. Because the dirty indicator is set internally, the first block below can be replaced with the second:
// first block
$("#childGrid").data("kendoGrid").dataItem(this.element.closest("tr")).set("ParentDropDown", this.dataItem().ToJson());
if (e.action == "itemChange") {
e.items[0].dirtyFields = e.items[0].dirtyFields || {};
e.items[0].dirtyFields[e.field] = true;
}
// second block
$("#childGrid").data("kendoGrid").dataItem(this.element.closest("tr")).set("ParentDropDown", this.dataItem().ToJson());
2. But I still need to include a check for the dirty flag and append the dirty flag class in the UI:
.ClientTemplate("#=dirtyField(data, 'ParentDropDown')# #=ParentDropDown.ParentName#")
// where dirtyField is a javascript function:
function dirtyField(data, fieldName) {
if (data.dirty && data.dirtyFields[fieldName]) {
return "<
span
class
=
'k-dirty'
></
span
>";
}
else {
return "";
}
}
My testing accorded with the above results, as I was able to remove the setting of the dirty flag, but I still needed the javascript function and the addition to the client template to show the dirty flag. (Since I am binding directly to ParentDropDown.ParentName, I also tried removing any reference to a client template, thinking that perhaps ".ClientTemplate("#=ParentDropDown.ParentName#")" was overriding a dirty flag class that was being included. But no such luck. The drop down did display and function properly without a call to .ClientTemplate() (at least, it appeared so), but the dirty flag indicator did not appear. It was only by including the extra "#=dirtyField(data, 'ParentDropDown')#" that I could see the dirty flag indicator.
Is the above correct?
Thanks,
Matt
I will take over the ticket as my colleague Konstantin is away.
I went over the communication and can confirm that the suggested approach by my colleagues could replace the original logic. Also, the ClientTemplate is needed as well in order to call the function.
If the flag has to be added via CSS(and HTML) based on the code I can assume that the model modification and setting the flag visually can be done together in the same function without the need of a separate one. Instead of returning only the span I can suggest returning the span and the value of the DropDown and only the value if the condition is not met.
If this is not possible, please provide an example demonstrating the issue and we will gladly provide a suggestion best suited for it.
Regards,
Stefan
Progress Telerik