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')
}
]
});
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;
}
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;'
})
}
]
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.

Share Post:

What to Read Next

For more insights into using the RowEditor plugin, you might want to read Using the ExtJS Row Editor, which covers its installation and basic usage for CRUD operations. Additionally, exploring Printing grids with Ext JS could be beneficial to understand methods for effectively printing grid data, complementing your knowledge of grid manipulation and presentation.