How To: Create Linked Remote Comboboxes in ExtJS
Posted by John Kleijn • Saturday, May 24. 2008 • Category: JavaScriptExtJS is a pretty awesome JavaScript library, that allows you to build user interfaces that are as easy to use as the ones found in desktop applications. Some of it's implementation is fairly complicated, and the amount of options and classes can be a bit overwhelming. I've learned a lot of new tricks lately, one of which I'm going to share with you in this post: creating 'linked' remote comboboxes.
Once you know how, it turns out to be stunningly simple
I'm not covering the very basics of using ExtJS (in this case, creating a form), check out the ExtJS site for plenty of examples and tutorials on ExtJS basics.
Ok, lets start with a basic FormPanel:
new Ext.FormPanel({
border: false,
fileUpload: false,
height: 300,
width: 400,
labelWidth: 100,
items: []
});
Now adding two comboboxes with remote stores.
new Ext.FormPanel({
border: false,
fileUpload: false,
height: 300,
width: 400,
labelWidth: 100,
items: [
new Ext.form.ComboBox({
triggerAction: 'all',
name: 'category',
mode: 'local',
lazyInit: true,
displayField: 'name',
valueField: 'id',
forceSelection: true,
typeAhead: true,
inputType:'text',
fieldLabel: 'Category selection',
store: new Ext.data.JsonStore({
autoLoad: true,
url: '/somecontroller/someaction/categories',
root: 'rows',
fields:['id', 'name']
})
}),
new Ext.form.ComboBox({
triggerAction: 'all',
name: 'item',
mode: 'local',
lazyInit: true,
displayField: 'name',
valueField: 'id',
forceSelection: true,
typeAhead: true,
inputType:'text',
fieldLabel: 'Item selection',
store: new Ext.data.JsonStore({
autoLoad: true,
url: '/somecontroller/someaction/items',
root: 'rows',
fields:['id', 'name']
})
})
]
});
Note that these stores get a chunk of JSON from the server at the specified URI and uses the contents as items. This JSON simply represents a multidimensional array, with primary key => display value rows. Same as a basic HTML select, really.
The store's configuration parameter 'autoLoad' has the store load the data without explicity having to invoke the load() method.
If you have included the ExtJS library, setup the document, and got a controller on the server side that spits out the appropiate JSON, you should now have two (very unexciting) comboboxes. One displaying categories, one all (!!!) items.
Of course, the goal is to only display the items that belong to the category selected in the first combobox. To accomplish this, we add a listener to the first combobox that responds to the user making a category selection by updating the item combo. We first add a 'listeners' property to the first combo's config literal:
listeners: {
select: {
fn:function()
{
alert('Yay.');
}
}
}
This will cause an alert to show whenever the combo's 'select' event is fired. Now we need to give the anonymous function access to the second combo, so it can reload it's store. The easiest way to do this (though arguably a bit dirty) is assigning an explicit ID to the second combo and using Ext.getCmp(). Best compare it with a Registry of sorts (if only because it feels a little less dirty then
).
listeners: {
select: { fn:
function()
{
Ext.getCmp('itemBox').clearValue();
Ext.getCmp('itemBox').store.load({
params:{ filter: this.value, filterfield: 'category_id'}
});
}
}
}
Note that I gave the items box the id 'itemBox'. The listeners property is set on the category box. The 'params' object is sent to the server via POST at the specified URI (of the items box). I'm passing two parameters that will get me list of items filtered by category ID, but you can specify whatever needed to get a filtered list in the second combo in your server setup.
This already accomplishes what we set out to do: when selecting a category, our list of items is filtered by category ID. Cool stuff eh?
But, let's assume you want to give your (now linked) comboboxes a default selected value. With a local store, you can simply set the 'value' config property on the server containing the ID, and the combo will automatically select the right item.When using a remote store, the combo is rendered first, then loads the store, even with 'autoLoad'. Consequently, when you set 'value' to the ID of the wanted selection, it doesn't trigger the selection of item in the store. Instead it just displays the ID. Ouch, trouble in paradise.
To fix this, we have to manually select the right item after the store is loaded. We again add a 'listeners' property, to the store this time, which contains a callback that fires on the 'load' event.
For this, I'm using a basic PHP template (using the default View in Zend Framework) that inserts the primary key of the item we want selected into a JS template containing our form. But again, insert whatever you need to, to get the primary key parsed into the JS.
Our category combo's store now looks like this:
new Ext.data.JsonStore({
autoLoad: true,
url: '/somecontroller/someaction/categories',
root: 'rows',
listeners: {
load: {
fn: function() {
Ext.getCmp('categoryBox').setValue(categoryId; ?>);
}
}
},
fields:['id', 'name']
})
Voila, the default/stored category is selected after the store is loaded. You can do the same with the items store.



ShareThis