1. #1
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default EXTJS 3.2.1 - Editorgridpanel - combobox using JSON store. [SOLVED]

    EXTJS 3.2.1 - Editorgridpanel - combobox using JSON store. [SOLVED]


    Hi,

    I have an editor grid panel with a combobox.
    I cannot display the text instead of the value of the options.
    After investigation and search, it seems that the problem is that the renderer to render the cell is called BEFORE the store's loading.
    I already stried the patch suggested in the ComboBox FAQ and other solution but still have the same problem.
    Here is a snapshot of my code for the store :
    Code:
    kmxgz.ordercmpappro.prototype.getCmpapproStore = function(my_url) {
     var myStore = new Ext.data.Store({
      proxy: new Ext.data.HttpProxy({
           url: my_url
         , method: 'POST'
        })
      , reader: new Ext.data.JsonReader({
             root: 'rows',
             totalProperty: 'total',
             id: 'list_cmpappro_id',
             fields: [
                        {name: 'list_cmpappro_id', mapping: 'list_cmpappro_id'}
                       , {name: 'list_cmpappro_name', mapping: 'list_cmpappro_name'}
                 ]
          })
      , autoLoad: true
        , id: 'cmpapproStore'
         , listeners: {
                    load: function(store, records, options){
                  //store is loaded, now you can work with it's records, etc.
                  console.info('store load, arguments:', arguments);
                  console.info('Store count = ', store.getCount());
           }
           }
     });
     return myStore;
    };
    The combo:
    Code:
    kmxgz.ordercmpappro.prototype.getCmpapproCombo = function(my_store) {
     var myCombo = new Ext.form.ComboBox({
         typeAhead: true,
         lazyRender:false,
          forceSelection: true,
         allowBlank: true,
         editable: true,
          selectOnFocus: true,
          id: 'cmpapproCombo',
         triggerAction: 'all',
         fieldLabel: 'CMP Appro',
         valueField: 'list_cmpappro_id',
         displayField: 'list_cmpappro_name',
         hiddenName: 'cmpappro_id',
      valueNotFoundText: 'Value not found.',
         mode: 'local',
         store: my_store,
         emptyText: 'Select a CMP Appro',
            loadingText: 'Veuillez patienter ...',        
         listeners: {
    
                    // 'change' will be fired when the value has changed and the user exits the ComboBox via tab, click, etc.
                    // The 'newValue' and 'oldValue' params will be from the field specified in the 'valueField' config above.
                    change: function(combo, newValue, oldValue){
                        console.log("Old Value: " + oldValue);
                        console.log("New Value: " + newValue);
                    },
    
                    // 'select' will be fired as soon as an item in the ComboBox is selected with mouse, keyboard.
                    select: function(combo, record, index){
                        console.log(record.data.name);
                        console.log(index);
                    }
                }
    
     });
     return myCombo;
    };
    And the renderer in the column model for the grid:

    Code:
    [...]
    
                              ,{
                                    id:            columnName2,
                                    header:            columnNameHeader2,
                                    dataIndex:        columnName2,
                                    //renderer:         Ext.util.Format.comboRenderer(_self.kmx_cmpappro_combo),
                                    align:            _KMX_EXT_CSS_LEFT_,
                                    width:            100,
                                    sortable:        false,
                                    hidden:            false,
                                    resizable:         true,
                                    filter:         false,
                                    editor:            _self.kmx_cmpappro_combo,
                                    editable:         true,
                                    menuDisabled:     true,
                                    hideable:        true,
                                    fixe:            false,
                              }
    [...]
    And the patch:
    Code:
    // create reusable renderer for ComboBox
    Ext.util.Format.comboRenderer = function(combo){
        return function(value){
            var record = combo.findRecord(combo.valueField || combo.displayField, value);
            return record ? record.get(combo.displayField) : combo.valueNotFoundText;
        }
    }
    
    /**
     * @class Ext.grid.ComboColumn
     * @extends Ext.grid.Column
     * <p>A Column definition class which renders a ComboBox field based on the Column's configured
     * editor. See the {@link Ext.grid.ColumnModel#xtype xtype} config option of {@link Ext.grid.ColumnModel}
     * for more details.</p>
     */
    Ext.grid.ComboColumn = Ext.extend(Ext.grid.Column, {
        constructor: function(cfg){
            Ext.grid.ComboColumn.superclass.constructor.call(this, cfg);
            this.renderer = Ext.util.Format.comboRenderer(this.editor.field ? this.editor.field : this.editor);
        }
    });
    
    // apply the custom column type to the prototype
    Ext.apply(Ext.grid.Column.types, {
        combocolumn: Ext.grid.ComboColumn
    });
    
    // Form submits displayField instead of valueField: the store has to be loaded BEFORE setValue().
    Ext.override(Ext.form.ComboBox, {
        setValue : function(v){
    //begin patch
            // Store not loaded yet? Set value when it *is* loaded.
            // Defer the setValue call until after the next load.
            alert('this.store.getCount() = ' + this.store.getCount());
            if (this.store.getCount() == 0) {
                this.store.on('load',
                    this.setValue.createDelegate(this, [v]), null, {single: true});
                return;
            }
    //end patch
            var text = v;
            if(this.valueField){
                var r = this.findRecord(this.valueField, v);
                if(r){
                    text = r.data[this.displayField];
                }else if(this.valueNotFoundText !== undefined){
                    text = this.valueNotFoundText;
                }
            }
            this.lastSelectionText = text;
            if(this.hiddenField){
                this.hiddenField.value = v;
            }
            Ext.form.ComboBox.superclass.setValue.call(this, text);
            this.value = v;
        }
    });
    Attached Images
    Last edited by kiminox; 20 May 2010 at 12:39 AM. Reason: SOLVED

  2. #2
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    91
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    You need to load the combobox store first and then the grid store.

    (or you need to return both the id and the text in the grid store and add some extra code to keep both in sync)

  3. #3
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default


    Actually, the combobox store is loaded using ajax call: so, it's asynchronous.
    That means I cannot control the time of loading: even if I load the store of the combobox BEFORE loading the grid, the problem will be the same.
    But your second idea:"to return both the id and the text in the grid store and add some extra code to keep both in sync", what does it mean?
    Where shoud I return the id and the text?
    Thank you

  4. #4
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    91
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    Sure you can:
    Code:
    comboboxStore.load({
      callback: function(){
        gridStore.load();
      }
    });
    (and remove the autoLoads)

  5. #5
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default


    ok thank you Condor but if I have more than 1 combobox, do how to do?
    This is a problem: one Ajax call for each combobox (per cell in the editor grid) but I should load the grid only when all the Ajax calls are done no?

  6. #6
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default Callback to load combobowx stores

    Callback to load combobowx stores


    Actually, I found a way: load the stores of the comboboxes with the callback functions...and the last callback loads the grid!
    Example of my code:
    Code:
    // load combobox stores BEFORE grid
        this.kmx_cmpappro_store.load({
            callback: function() {
                _self.kmx_order_store.load({
                    callback: function() {
                        my_grid.store.load({params:{start:0,  limit:_self.kmx_pagination_page_size}});
                    }
                });
            }
        });
    Somebody has a better way to achieve that?
    It works but well, I am not really satisfied.
    And if I click on the "load" button of the grid, I have to do something again ?
    Thank you Condor anyway.

  7. #7
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    91
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    I would rewrite my server app to return all the data (comboboxes + grid) in one request.
    Then you can load the comboboxes first and then the grid with the retured data.

  8. #8
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default


    Actually, that's what I did: I defined a reusable editor grid panel with some common buttons/actions: each child class must redefine the column model, the stores, the record, the url to save/delete...
    my_editor_grid_panel.png

    Fortunaly!
    If somebody is interested, I can share my code with you: that's why I love OPEN SOURCE!

  9. #9
    Ext User
    Join Date
    May 2010
    Location
    China, Zhejiang province, Ningbo City, a small city of 5 million people..
    Posts
    12
    Vote Rating
    0
    kiminox is on a distinguished road

      0  

    Default


    Actually,

    There's a problem with the reloading button/action: when I modified the data, the grid auto-reloads itself (or when I click on the button refresh). Then the grid refreshs itself but without refreshing the combobox stores.
    Question: how can I change the behavior of the refresh action? Do I override the load button/refresh ? How?
    I found something:
    Code:
    Ext.override(Ext.data.Store, { 
            startAutoRefresh : function(interval, params, callback, refreshNow){ 
                if(refreshNow){ 
                    this.load({params:params, callback:callback}); 
                } 
                if(this.autoRefreshProcId){ 
                    clearInterval(this.autoRefreshProcId); 
                } 
                this.autoRefreshProcId = setInterval(this.load.createDelegate(this, [{params:params, callback:callback}]), interval*1000); 
            }, 
            stopAutoRefresh : function(){ 
                if(this.autoRefreshProcId){ 
                    clearInterval(this.autoRefreshProcId); 
                } 
            }         
        });
    But it's a quite complex no? Thanks

  10. #10
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    91
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    I would recommend:
    Code:
    var grid = new Ext.grid.EditorGridPanel({
      ...
      viewConfig: {
        ...
        onDataChange: function(store){
          combobox1.store.loadData(store.reader.jsonData);
          combobox2.store.loadData(store.reader.jsonData);
          this.constructor.prototype.onDataChange.apply(this, arguments);
        }
      }
    });

Thread Participants: 2

Tags for this Thread