Making RowEditor use your column renderers

The RowEditor plugin is one of my favourite Ext JS components. It basically allows any row on a grid to be turned into an adhoc form on the fly, saving you the effort of defining additional form components.

Recently I had a grid which had a few fields that don’t have an editor, something like this:

var myGrid = new Ext.grid.GridPanel({
  plugins: [new Ext.ux.grid.RowEditor()],
  columns: [
    {
      header   : "Username",
      dataIndex: 'username',
      editor   : new Ext.form.TextField()
    },
    {
      header   : "Signup date",
      dataIndex: 'created_at',
      renderer : Ext.util.Format.dateRenderer('m/d/Y')
    }
  ]
});

Simple stuff – we just show a username and a signup date, which is altered by a renderer. When we double-click a row it turns into an editable row, and we get a textfield allowing us to edit the username. Unfortunately, while in edit mode our date renderer is ignored, and the raw value displayed instead.

Thankfully, we can fix this by altering RowEditor’s source code. The method we need to change is startEditing, which sadly suffers from long method syndrome. About halfway into that method there’s a for loop, which we’re going to alter to look like this:

for (var i = 0, len = cm.getColumnCount(); i < len; i++){
  val = this.preEditValue(record, cm.getDataIndex(i));
  f = fields[i];
  
  //our changes start here
  var column = cm.getColumnById(cm.getColumnId(i));
  
  val = column.renderer.call(column, val, {}, record);
  //our changes end here
  
  f.setValue(val);
  this.values[f.id] = Ext.isEmpty(val) ? '' : val;
}

We didn’t really have to do much, just grab the renderer for the column and pass it the default value and the record which was found earlier in the method.

For the curious, the empty object we pass in as the second argument to the renderer is what would usually be the ‘meta’ object (see the renderer documentation on the Column class). Under the covers, RowEditor actually creates an Ext.form.DisplayField instance for each column that you don’t specify an editor for. This is why we use f.setValue(val); above. DisplayField doesn’t have the same meta stuff as a normal cell would, so if you’re looking to customise CSS via the metadata you’ll have to do something like this instead:

columns: [
  {
     ...
    editor: new Ext.form.DisplayField({
      cls: 'myCustomCSSClass',
      style: 'border: 10px solid red;'
    })
  }
]

Pretty easy. It’s a shame we have to overwrite the source code as this makes the solution less future proof, but if you look at RowEditor’s source code you’ll see why a 45 line override would be equally unpleasant.

12 Responses to Making RowEditor use your column renderers

  1. Royce says:

    Hi Ed, 1st congrats on your new position at ExtJS. I am glad you recognize how ‘challenging” ExtJS can be for us newbies and I hope you can shorten the learning curve for those of us who aren’t OO JS experts! I just read your post on getting the row editor to use a column renderer and I’m trying to do something similar. I would like the row editor to use my remote combo box for certain columns.

    Do you have any ideas on how this can me done?

    regards,
    Royce

  2. Dipish says:

    Royce, i don’t see a problem here. Just assign a ‘editor: new Ext.form.ComboBox({…’ with mode: ‘remote’ to a column.

    Ed Spencer, thanks for interesting post! I would like to suggest another solution to the problem described in this post. The other way to show uneditable fields in RowEditor is just specifying an Ext.form.DisplayField as a column editor and that’s it! No RowEditor.js modifying. Sometimes this might be a better solution.

    Regards,
    Dipish.

  3. xpete says:

    Why this change is not included in RowEditor?

  4. Ed Spencer says:

    @xpete I’ll suggest this to Aaron, who is rewriting this component

  5. Urs says:

    Works fine, but if the renderer does things like including span tags or more complex formating you will get problems because the val you tries to set contains all this stuff.
    I would sugest to include an if statement before line 08

    if(typeof column.editable!=’undefined’ && !column.editable){

  6. drowsy says:

    Thank you for this plugin, it is great!

    I ran into a situation where I was rendering dates in non-edited columns from my store, and they were coming out in whatever default format extjs was using. So I applied your changes above and then all the rows looked consistent in editing and viewing.

    The only issue was that the reformating was viewed as a ‘change’ in data and was returned in the update action to the server.

    So I added a check for a column.editor in the stopEditing/saveChanges function:

    //our changes start here
    var column = cm.getColumnById(cm.getColumnId(i));
    if(column.editor){
    if(String(oldValue) !== String(value)){
    changes[dindex] = value;
    hasChange = true;
    }
    }
    //our changes end here

  7. Ed Spencer says:

    @drowsy nice catch. We’re rewriting RowEditor for Ext JS 4 so will be sure to perfect it so that it doesn’t need plugins like this!

  8. Pingback: extjstutorial.org

  9. Tadeo says:

    Hi, i have a question, with this piece of code can i resolve f.is undefined?
    Example:
    When i Run for First Time my Form with a Raw Editor, all is Fine, but if i close my Form , and then i decide to open my form Again , and if i try to edit the Raw editor , Firebug rise a bug: f is undefined in RawEditor.js line:
    f.setValue(val);
    this.values[f.id] = Ext.isEmpty(val) ? ” : val;

    Thank you

  10. Tadeo says:

    Hi Again , i forgot to tell ya sothing , The f is undefined rised, when i close my form with action:’close’,
    and before call my form again, i do first: MyDataStore.removeAll();

    F is undefined , is a bug from this line: fields = this.items.items
    so if f is empty :
    f = fields[i];
    .
    .
    .
    f.setValue(val); ////<—–Here Rise the bug.

    Thank you

  11. Mike says:

    Hello, Thank you for your update. It certainly helped. However, if the grid has an editable checkbox (i.e. xtype: ‘booleancolumn’), then the value is always reset to uncheck (even though initial value was checked). Could you please provide a solution for that?

    Thank you.

  12. kprk says:

    Hi Ed,
    I am using roweditor and action column in a grid panel. After clicking on action column button and when I try to click on roweditor , it doesn’t work. and throws exception as Uncaught TypeError: Cannot set property ‘value’ of undefined.Could you please suggest anything ?
    –kprk

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: