THE BLOG

News, tips and tricks from 2Gears

ComboBox editor (remote) and renderer for ExtJS EditorGridPanel

Posted · 45 Comments
HTML5 white grey 60px

Adding a ComboBox editor to a ExtJS EditorGridPanel column can by tricky if your ComboBox uses a remote store. This post demonstrates using a custom grid column type and associated renderer to solve this problem.

ExtJS EditorGridPanel

The ExtJS EditorGrid Panel is excellent for editing records from within the grid. The component allows one to specify an editor type per column. The ExtJS 3 examples show a nice example of this

The problem

The editor works perfectly for columns in which the stored value is also the display value. The EditorGridPanel also allows for a ComboBox to be used as the editor. When the displayField and valueField of the combobox are the same this works ok, but less so for columns that are for instance foreign keys into other models. An example illustrates this:

In this example the Assignee column lists the ID’s of users. A ComboBox has been specified as the editor. When editing the field, the ComboBox comes into action and correctly lists the Users by name:

After selecting a User the column value is updated with the user’s id. This allows us to change the column value easily, but of course this is not what we want. Wat we actually want is to display the User’s name in the grid, hiding the value. At the same time the column’s raw value should still be the user id:

A number of specialized ComboBox renderers have been published in the Sencha forum that allow to do just this. The renderer looks up the corresponding record in the ComboBox’s store by it’s valueField and returns the corresponding displayField. For ComboBoxes with local stores that usually works but without hacks this will not fly for ComboBoxes with remote stores such as a JsonStore or DirectStore. This has to do with the fact that at the time the grid is created and the custom renderer is asked for the record’s displayField the ComboBoxes store has not finished loading yet. The only times this does work is if you get luck and win the race condition… Not what we want at all in production applications.

The solution

I am releasing a custom grid column with associated renderer that solves exactly this problem. The only thing the column configuration needs is the EditorGrid’s id and an editor that we are specifying anyway. The renderer is setup automatically. The way this works is that the renderer checks if the ComboBox editor’s store has already been loaded. If this is not the case it sets up a one-time event listener on the ComboBox store’s ‘load’ event. The event handler lets the Editor Grid’s view refresh, essentially re-calling the columns renderers. This time the store is loaded and the record and displayField can be found.

The following code snipped explains the configuration neccessary:

/* create the ComboBox editor */
var userCombo = new Ext.ComboBox({
	id: 'myCombo',
	valueField:'id',
	displayField:'name',
	store: ...
});

/* We need a unique id for the grid, either create one yourself or let Ext create it for you */

var gridId = Ext.id();

/* Create the grid */

var todoGrid = new Ext.grid.EditorGridPanel({
	store: myStore,
	id: gridId, 					// Be sure to include the grid id
	cm: new Ext.grid.ColumnModel({
		columns: [{
			id: 'todo',
			header: 'Todo',
			dataIndex: 'todo'
		},{
			id: 'owner',
			width: 150,
			header: 'Assignee',
			dataIndex: 'owner',
			xtype: 'combocolumn', 	// Use the custom column or use the column's render manually
			editor: userCombo,		// The custom column needs a ComboBox editor to be able to render the displayValue, without it just renders value
			gridId: gridId			// Don't forget to specify the grid's id, the columns renderer needs it
		}]
	}),
	clicksToEdit: 1
});

And VOILA, an EditorGrid that displays the record by it’s displayField while still functioning exactly the same and also working with remote stores. The complete custom column specification and renderer is displayed below and also attached as a zip file.

Good luck and don’t forget to share this post if it’s of use to you, it might also be to others.

Rob

Ext.ux.ComboColumn source file

45 Responses to "ComboBox editor (remote) and renderer for ExtJS EditorGridPanel"
  1. Stosloff says:

    Hi! I found an issue when the store looks like:
    id – name
    1 – Z
    2 – A
    3 – B
    4 – C
    5 – D
    6 – E
    7 – F
    8 – J
    9 – H
    10 – E
    11 – J
    12 – K
    13 – L

    And I select ‘Z’ in my result sorted combobox – I will get ‘E’ in field (when it is shown as not combo).

    My replacement is:
    > var idx = combo.store.find(combo.valueField …
    with
    > var idx = combo.store.findExact(combo.valueField …

    helps in this case. But I’m still not sure that this is the problem.

    Thank you.

    • Stosloff says:

      Sorry, I mean “10 – I” instead of “10 – E”. But anyway, it will show ‘I’ in this case.

      Because .find() will return ’10′ for the ’1′ search key as ’10′ is the first appropriate value in this store (“1 – Z” will be the last in case of sorted store)

      Thank you.

      • Rob Boerman says:

        Hi there, I will take a look at your use case when I get a chance this weekend otherwise next week during some time off at SenchaCon

  2. Cj says:

    Hi,

    Thanks very much for posting this. I managed to get it working in ExtJS 4.1.1 using the following adaptation of your initial code:

    Create a new Class:

    Ext.define('Ext.app.ux.ComboColumn', {
    extend: 'Ext.grid.column.Column',
    alias: 'widget.combocolumn',

    gridId: undefined,

    initComponent: function() {
    this.callParent(arguments);

    this.renderer = (this.editor && this.editor.triggerAction) ? ComboBoxRenderer(this.editor, this.gridId) : function(value) {return value};};
    }
    })

    And then the ComboBoxRenderer function

    function ComboBoxRenderer(combo, gridId) {
    var getValue = function(value) {
    var idx = combo.store.find(combo.valueField, value);
    var rec = combo.store.getAt(idx);

    if (rec) {
    return rec.get(combo.displayField);
    }
    return value;
    }

    return function(value) {
    if (combo.store.getCount() === 0 && gridId) {
    combo.store.on(
    'load', function() {
    var grid = Ext.getCmp(gridId);
    if (grid) {
    grid.view.refresh();
    }
    }, {
    single: true
    }
    );
    return value;
    }

    return getValue(value);
    };
    }

    I hope this helps anybody out that is struggling to get this working with Ext 4.

    • Rob Boerman says:

      Great, thanks for the port, I will check your code out. I also made some adjustments to make it more ExtJS 4 proof, will update the post one of these days

  3. Tom says:

    This rocks!

  4. ernesto says:

    the plugin is very useful and very easy to use thanks

  5. Aditya says:

    is the ‘Ext.grid.editorgridpanel’ working in ExtJS4.0???

  6. Luke says:

    Hey Rob! Any luck with 4.0?

    Thanks

    • Rob Boerman says:

      Hey Luke,

      Unfortunately I haven’t had time yet. Currently porting the Sencha Touch Timepicker over to ST2. After that I will try to find time for this one but the next 2 weeks are completely full

Leave a Reply

Your email address will not be published. Required fields are marked *

six + 3 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>