Cascading ComboBoxes in ExtJS EditorGridPanel
I have a working EditorGrid panel, where two columns have ComboBox editors. Both ComboBoxes are loaded remotely from database (countryStore
and cityStore
).
I would like to limit the cityComboBox
to show only cities in the selected country. I need to reload the cityStore
with a filter from database (there are too many cities to filter localy). The filter value is the countryComboBox
value.
There is always a value in countryComboBox, because I add a default = 1开发者_开发技巧 when creating a new record, so this isn't a problem.
I don't know which listener would be appropriate here. I need to catch the moment when I double click on the country cell, before the countryComboBox
shows up and filter the combo box before it's shown (or display a waiting message while it's retrieving data).
If this is not possible, could I open a popup window by double clicking a cell, choose from a comboBox of filtered cities, "confirm" and enter the value into the cell?
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.
I can see a couple options here. You could catch the store's update
event (when the underlying record is updated or marked dirty) or catch the countryComboBox's select
event. Both of those will provide you with the id value of the selected country, which you can then add to your cityComboBox's baseParams
for remote filtering.
精彩评论