23
votes

I'm just wondering how you go about changing a value of a row in a grid in JavaScript so that it is marked as 'dirty' in the grid and the underlying datasource.

e.g. I have a list of Contact/Customer. They have 3 fields FirstName/LastName/IsPrimaryContact. There can only be 1 primary contact, so when the primary contact is set to true on a record I have JavaScript code that loops through the datasource and sets any other contacts set as primary to false.

The JavaScript all fires fine and the data fields are set correctly but there are two problems: 1. The grid is not updated with the changes I make under the hood to the datasource 2. The records changed are not marked as "dirty" and therefore not sync'd back when I call a Datasource.sync()

I can fix the second issue by manually setting the dirty field on the record, but this doesn't seem right. It feels like I should be updating the field at the grid level so that it takes care of it in both the UI and the datasource.

Any ideas on how to go about this?

Thanks

6

6 Answers

42
votes

Basically when you want to update a record you should use the set method of the model. For example to update the first record of the dataSource you should update it like this:

var firstItem = $('#GridName').data().kendoGrid.dataSource.data()[0];
firstItem.set('FirstName','The updated Name');

The above should automatically mark the flag as dirty and it will notify the Grid that there are changes, so the Grid will automatically refresh.

Also if you want to retrieve the object related to a specific row directly you could use the dataItem method of the Grid.

7
votes

I do it in a very simple and effective way:

 var employee = employeeDataSource.get(employeeId);
     employee.dirty = true;  // set it as dirty
     employeeDataSource.sync();  //Tell the DataSource object to save changes

It's an old question but hope it may help anyone with the same issue.

4
votes

Following Pechka answer above, i added some additional code to mark the edited cell with dirty flag.

Here's my razor code needed on the column for this to work, i added a class name so it can be used in the jquery selector later.

columns.Bound(r => r.RoomRate).HtmlAttributes(new { @class = "grid-allotment-roomrate" });

Here's my Jquery code to update the cell and mark the edited cell after a success data retrieval from server side.

var dataSource = $("#grid-allotments").data("kendoGrid").dataSource;
var data = dataSource.data();
$.each(data, function (index, rowItem) {
    var checkbox = $("#checkbox_" + rowItem.RoomTypeId + "_" + rowItem.Date.getTime());
    if (checkbox != null && checkbox.is(':checked')) {
        $.ajax({
            url: "RackRate/GetRackRateForRoomTypeOn",
            type: "POST",
            data: { roomTypeId: rowItem.RoomTypeId, date: rowItem.Date.toUTCString() },
            success: function (result) {
                data[index].set('RoomRate', result);
                $('tr[data-uid="' + rowItem.uid + '"] .grid-allotment-roomrate').prepend('<span class="k-dirty"></span>');
            }
        });
    }
});

Below is the line of code that is responsible for the dirty flag highlight.

$('tr[data-uid="' + rowItem.uid + '"] .grid-allotment-roomrate').prepend('<span class="k-dirty"></span>');
2
votes

I use it this way - at least with checkboxes. I'll set the column with the Edit button to look like this:

columns.Command(command => {command.Edit().HtmlAttributes(new { id = "btnEdit_" + "${Id}" }); }).Width(100).Hidden(true);

And have it where clicking into the first column (I have an image with a hyperlink) uses an onclick function to programmatically click the Edit button, click the checkbox, then click the Update button. Probably more "old school", but I like knowing it is following the order I would be doing if I were updating it, myself.

I pass in the object ("this"), so I can get the row and checkbox when it appears, the new status as 0 or 1 (I have some code that uses it, not really necessary for this demo, though, so I'm leaving that part out of my function for simplicity), and the ID of that item:

columns.Bound(p => p.IsActive).Title("Active").Width(100).ClientTemplate("# if (IsActive == true ) {# <a href=javascript:void(0) id=btnActive_${Id} onclick=changeCheckbox(this, '0', ${Id}) class='k-button k-button-icontext k-grid-update'><img style='border:1px solid black' id=imgActive src=../../Images/active_1.png /></a> #} else {# <a href=javascript:void(0) id=btnActive_${Id} onclick=changeCheckbox(this, '1', ${Id}) class='k-button k-button-icontext k-grid-update'><img style='border:1px solid black' id=imgActive src=../../Images/active_0.png /></a> #}#");

function changeCheckbox(obj, status, id) {
    var parentTr = obj.parentNode.parentNode;
    $('[id="btnEdit_' + id + '"]').click();

    parentTr.childNodes[5].childNodes[0].setAttribute("id", "btnUpdate_" + id); // my Update button is in the 6th column over
    parentTr.childNodes[0].childNodes[0].setAttribute("id", "chkbox_" + id);
    $('[id=chkbox_' + id + ']').click().trigger("change");
    $('[id=chkbox_' + id + ']').blur();

    var btnUpdate = $('[id="btnUpdate_' + id + '"]');
    $('[id="btnUpdate_' + id + '"]').click();

}

Code above assumes, of course, the checkbox is in the first column. Otherwise, adjust the first childNodes[0] on that chkbox setAttribute line to the column it sits in, minus one because it starts counting from zero.

2
votes

For me works this (No need to instantiate grid):

   select: function(e) {
           console.log("select");
           var item = e.item;
           var text = item.text();
           var index = item.index();
           console.log(item);
           console.log(text);
           console.log(index);
           var dataItem = this.dataItem(index);
           console.log(dataItem);
           // SET RETURNED VALUES FOR MODEL
           options.model.set("actionName.id", dataItem.id);
         }
0
votes

set("fieldname",value) will refresh the grid automatically, there is one simple way to just update both the UI value and the field value without any need to do refresh. just do, eg:

    data.FieldName = "Whatevervalue";
    $(currentrow.children()[getColumnIndex("FieldName")]).text("Whatevervalue");

    function getColumnIndex(columnName) {
    var index;
    var columns = $("#grid").data("kendoGrid").columns;
    for (var i = 0; i < columns.length; i++) {
        if (columns[i].field == columnName) {
            index = i;
            return index;
        }
    }
}

    var data = $grid.data("kendoGrid")._data;
    var currentrow = $grid.data("kendoGrid").tbody.find("tr[data-uid='" +      data[i].uid + "']");

Hope this helps