I finally made it work. I created two solutions - for local and remote dropdown searches within the grid. In the end, I decided to use a local search (I can add country_id
to my cities
query and filter in ExtJS), but it's possible to make this work for remote searches - if anyone needs that, I can prepare that solution too.
LOCAL SOLUTION
I had to filter cityCombo
using a beforeQuery event, using the id from countryCombo
in the same row. Here's the code for cityCombo
:
var cityCombo = new Ext.form.ComboBox({
triggerAction: 'all',
mode: 'local',
lastQuery: '', // to make sure the filter in the store is not cleared the first time the ComboBox trigger is used
store: cityDropdownStore,
displayField: 'city',
valueField: 'city_id',
listeners: {
beforeQuery: function(query) {
currentRowId = myGrid.getSelectionModel().getSelected().data.country_id;
this.store.clearFilter();
this.store.filter( { property: 'country_id', value: currentRowId, exactMatch: true } );
}
}
});
As you can see, when the cityCombo
inside the grid is double clicked, I get country_id
in the current row and filter cityStore
using that value. This requires cityStore
to have these fields: id
, country_id
, city
One problem still remains: when the user changes the countryCombo
, the city field should change / warn the user that it's not correct for the current country. The solution for this was complicated... as you may know, you cannot get a reference to a comboBox's parentGrid (otherwise you could just call countryCombo --> parentGrid --> currentRecord --> cityCombo --> change it
).
I tried listening to the rowchange event on the grid itself, but if a user clicked to another row directly after changing countryCombo
, it changed the wrong row's city.
The solution was somewhat advanced: I had to copy references for current row to cityCombo from the grid's beforeedit event. Here's the grid's listener for this:
listeners: {
beforeedit: function(e) {
// reference to the currently clicked cell
var ed = e.grid.getColumnModel().getCellEditor(e.column, e.row);
if (ed && ed.field) {
// copy these references to the current editor (countryCombo in our case)
Ext.copyTo(ed.field, e, 'grid,record,field,row,column');
}
}
},
Now our countryCombo
has all the information neccessary to reset the city when it gets changed. Here's the whole countryCombo
code:
var countryCombo = new Ext.form.ComboBox({
id: 'skupina_combo',
typeAhead: true,
triggerAction: 'all',
lazyRender: true,
mode: 'local',
store: countryDropdownStore,
displayField: 'country',
valueField: 'country_id',
listeners: {
change: function(t, n, o) { // t is the reference to the combo
// I have t.record available only because I copied it in the beforeEdit event from grid
t.record.set('city_id', '0');
}
}
});
Cell renderers didn't have a problem with me filtering their store, so I only needed one store for both rendering and comboBox editing (cityStore).
The remote solution required me to create two stores for cities - cityRendererStore
and cityDropdownStore
, which queried the database each time instead of using filters. That approach is neccessary if you have too many cities to filter locally. I should mention I'm not really using cities and countries in my application, I just created this example to simplify things.
I'm really happy about the end result - it gives all the benefits of a grid together with conditional dropdowns usually available only in forms.