Dojo Data Grid – Part 12: Highlighting Edited Rows

If you’ve implemented editable columns in your grid, it would be helpful to let users know which rows have been edited but not yet saved. In this post, I’ll show you how.

Dojo Data Grid Series

Row Change Event

In a previous post, I talked about the onStyleRow event that’s available to the grid. (Refer to that post for instructions on the proper way to add the event code.)

By inspecting the properties of the arguments automatically made available to that event, I found that the node has an onchange event handler available, so we can use that to track changes to the data.

Unfortunately, it is not cell-specific — as far as I can tell, you can only get a handle to the entire row.

Quick and Dirty Solution

The simplest way to use this logic is to add a function to the onchange event of the row node, from code within the onStyleRow event.

var row = arguments[0];
row.node.onchange = function () {
  row.node.style.backgroundColor = ' background-color:yellow;';
}

Now, when you edit a field in the grid, it will automatically highlight the row in yellow.

DataGrid_12_1

There are two problems with this method:

  1. It does not persist. Once you scroll far enough down in the grid, the style of that row is lost and will not be maintained when you scroll back, because the row is re-drawn and does not remember the style you added.
  2. It does not get cleared when you save or revert the changes in the grid. In my opinion, it makes the most sense to highlight a changed row and show that it has not yet been saved.

A Better (Persistent) Solution

To better keep track of the changes in the grid, you can use a global javascript variable on the page to keep track of an array of updated rows and refer to that array when styling the rows in the grid.

First, add an output script control to the page and set it’s code to this:

var editedRows = [];

Then, update the onStyleRow event code to (a) keep track of the row index when updated and (b) check whether the current row has been updated.

var row = arguments[0];

// If this row has been changed, highlight it
if (dojo.indexOf(editedRows, row.index) > -1) {
  row.customStyles += ' background-color:yellow;';
}

// Keep track of the changed row
row.node.onchange = function () {
  editedRows.push(row.index);
}

Since the list of updated rows is now in a global variable, it will persist, regardless of how much the user scrolls. (It will not persist if the entire page is refreshed, but neither would any unsaved changes.)

Lastly, update the Save and Revert buttons to clear that array and re-draw the grid, in order to force the highlighting to be removed once the changes are saved or reverted (because there’s nothing left to highlight at that point.)

This is what the Save button code now looks like:

// Reset the list of edited rows to clear the styles
editedRows = [];
var args = {onError: function() {alert('error!');}};
restViewItemFileService.save(args);

//Refresh the grid
restViewItemFileService.close();
dijit.byId('#{id:djxDataGrid1}')._refresh();

Much better!

Advertisements

9 responses to “Dojo Data Grid – Part 12: Highlighting Edited Rows”

  1. edm00se says :

    When implementing my xe:restService as a viewItemFileService, I’ve found that my restServiceID.revert() method now throws a curious error:
    “Uncaught ReferenceError: op is not defined”.

    Saving back via the grid works flawlessly, this only happens when I make a change, then hit my undo changes button. Any ideas what I may be running into?

    • edm00se says :

      It’s complaining about /xsp/.ibmxspres/.extlib/dojo/data/FileStore.js line 381, the if(op==1) statement in the revert function.

    • Brad Balassaitis says :

      Unfortunately, I don’t know off hand. I’ve had very inconsistent results with the revert() function. The good news is that if you refresh the grid, it essentially does the same thing, because it reloads the content and loses the unsaved changes. I’ll post something here if I come across a better solution.

      • edm00se says :

        Glad to know it’s not just me. I guess I figured I could roll a refresh should the need be. I’ll stay tuned, and thanks again for the great series!

      • Brad Balassaitis says :

        Thanks! I think the next one is the best one of the series.

      • Roman says :

        Does not work. I click Undo, after Save. New data is saved (not old data).
        I corrected code. Maybe someone will come in handy. Add this code(re-writed function setValue and revert) in onClientLoad ( i add attribute “oldAttrs” )

        restViewItemFileService.setValue = function( /* item */ item,
        /* string */ attribute,
        /* almost anything */ value){
        this._assertIsItem(item);
        this._assertHasAttribute(item, attribute);
        if (typeof value == ‘undefined’ || value === null)
        throw new Error(“TableStore.setValue: invalid parameter”);

        // Don’t allow changing the item’s identity
        if(attribute == this._identity){
        throw new Error(“TableStore does not support changing the value of an item’s identifier.”);
        }

        var id = this.getIdentity(item)
        var pending = this._pendings[id]
        if(!pending) {
        pending = {op:1, origAttrs: item.attributes, modAttrs:{}, oldAttrs:{}}
        this._pendings[id] = pending
        } else {
        if(pending.op==2) { // Deleted, do nothing
        return false;
        }
        // Created or modified, just continue
        }

        var oldValue = item.attributes[attribute];
        item.attributes[attribute] = pending.modAttrs[attribute] = value;
        if ( !pending.oldAttrs[attribute] )
        pending.oldAttrs[attribute] = oldValue;
        this.onSet(item, attribute, oldValue, value);
        return true; // boolean
        }

        restViewItemFileService.revert = function() {
        for(var s in this._pendings) {
        var p = this._pendings[s]
        if(p.op == 1) {
        for( var i in p.modAttrs) {
        p.modAttrs[i] = p.oldAttrs[i]
        }
        }
        }
        this.created = 0;
        return true;
        }

      • Brad Balassaitis says :

        The undo function is not intended to roll back saved changes. It is intended to indo changes that have not yet been saved.

      • Roman says :

        I’m testing a DataGrid and find a lot of bugs. Did no one else uses this DataGrid?

        Sorry for double post

      • Roman says :

        Yes, but..
        I have data “qwerty”. Change it to “asdfgh”. Click Undo. I see in datagrid “qwerty”. But after I click Save. And again I see in datagrid “asdfgh”!
        It’s magic 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: