views:

54

answers:

2

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?

+1  A: 

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.

wes
I tried the first suggestion already (store's `update` event), but it's not working - imagine I want to edit an existing record's City - I double click the city dropdown, there was no store change yet. The `select` on cityComboBox fires only when you select a value in the dropdown - I need it to be filtered before I select anything. The `select` on countryComboBox is not fired when editing an existing record's City only (same as `update store` problem).
Enorog
But you already know what the city combo should default to, since you're defaulting `country = 1` right? A code sample in your question showing your grid configuration and event handlers would be helpful :)
wes
Well, my code wouldn't do much good, because everything is working as far as dynamic dropdowns in editable grid go. I need the new code. Regarding your comment: yes, I always have country = 1 (or country = existing value in record), but my problem is how to filter the `cityCombobBox` on the current row's `countryComboBox` field (which I have).
Enorog
Well I guess I'm at a loss then. Perhaps you could catch the combo's `beforeQuery` event and read the record then for the param to filter on.
wes
I'll try `beforeQuery` - I know this is a complex situation, thank you for your suggestions. If I manage to make it work, I'll share the solution here.
Enorog
+1  A: 

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.

Enorog