0
votes

I know this has been asked somewhere again and again but I can't find a solid answer as standard for this kind of problem.

As many have done before I have an editor inside a grid that is a combobox that uses remote store from a database. Now suppose that there is a table in the database with 50,000 records. The combobox only loads the first 15. When I select a record between these 15 everything displays fine. To render the displayField instead the valueField, I use the following function

  renderCombobox : function(value, metaData, record, rowIndex, colIndex, store, view, isNewRow){      
      var me      = this,
          columns = me.columns,
          editor, editorStore, editorIndex, displayField, display, rec;

    for(var i=0,j=columns.length;i<j;i++){          
      if(columns[i].getEditor){
          editor = columns[i].getEditor(record);
          if(editor.xtype === 'combobox'){
              editorStore   = editor.getStore().load();
              editorIndex   = editorStore.findExact(editor.valueField, value);
              displayField = editor.displayField;
          }
      }
    }      
    if(editorIndex != -1){
        rec = editorStore.getAt(editorIndex);
        if(rec && rec.get(displayField)){
            display = rec.get(displayField);
        }               
    }      
    return display;        
}

The problem is the following scenario.

If I type ahead, I can find a record that is not between these 15 records. For example the record 42,300. I select it and for the moment everything is OK. Now If I click on another field on another editor in the grid (i.e. datefield) the renderer function for the combobox returns undefined as it tries to find the record with value of the record 42,300 that does not exist in the store. Debugger says that the store contains again only the first 15 records.

Is there any configuration I miss? The store needs a limitation. I can't bring 50,000 records from the database at once.

2
I think one approach is to use this.store.on({beforeload:somefns,load:somefns}). These two functions should be responsible to find the last value of the combobox that came from the database and insert it in the store with store.insert(0,record). So every time the first record will be that of the remote source. I'll have a try later this evening and come back in case I have a solution. This might be useful to someone else.dev

2 Answers

2
votes

I think that this example does exactly what you want: http://extjs.eu/ext-examples/#combo-in-grid

0
votes

The awesome Saki's article gave me the clue to solve this task.

You don't need any renderers, just add an additional store with all key-value pairs for your combo and add 'edit' event to the grid.

Here it is.

Your additional remote store :

Ext.define('crm.store.BillAdTarifsStore', {
    extend      : 'Ext.data.Store',
    storeId     : 'BillAdTarifsStore',
    requires    : 'crm.model.BillAdTarifsModel',
    model       : 'crm.model.BillAdTarifsModel',
    autoLoad    : true 
});

it's model:

Ext.define('crm.model.BillAdTarifsModel', {
    extend: 'Ext.data.Model',
    fields: [
        { name: 'id',        type: 'int'},
        { name: 'VarName',   type: 'string' }
    ],
    proxy   : {
        type    : 'ajax',
        url     : AjaxUrl,
        reader  : {
            type            : 'json',
            idProperty      : 'id',
            root            : 'data',
            totalProperty   : 'total',
            successProperty : 'success',
            messageProperty : 'message'
        },
        extraParams  : {
            Action   : 'DataRequest',
            DataType : 'GetBillAdTarifs'
        }
    }
});

Grid configuration:

plugins: [
    Ext.create('Ext.grid.plugin.CellEditing', {
        clicksToEdit: 1
    })
],
listeners: {
    // this event will change valueField in cell to the displayField (after choosing combo item)
    edit: function(e, eOpts) {
        // eOpts.rowIdx - is the index of row with clicked combo
        var SelectedComboId = Number(Ext.getCmp('ObjectsGrid').getStore().getAt( eOpts.rowIdx ).get('YourGridColumnName'));
        console.log( 'SelectedComboId: '+SelectedComboId );

        if(Number(SelectedComboId) > 0) {
            // ComboItemObj - get field name by index from additional store
            var ComboItemObj = Ext.data.StoreManager.lookup('BillAdTarifsStore').getById(SelectedComboId);
            if ( typeof ComboItemObj.data.id !== null && Number(ComboItemObj.data.id)>0 ) {
                // real combo item is chosen, set field name
                    Ext.getCmp('ObjectsGrid').getStore().getAt(eOpts.rowIdx).set('TrfCianBig',ComboItemObj.data.VarName);
            }
        }
    }

Column configuration can look like this:

editor  : new Ext.form.field.ComboBox({
    triggerAction : 'all',
    forceSelection: false,
    editable    : false,
    allowBlank  : true,
    displayField: 'VarName',
    valueField  : 'id',
    store       : Ext.data.StoreManager.lookup('BillAdTarifsComboStore'),
        listeners: {
                 'change': function(comp, newValue, oldValue, eOpts) {
                               // Selected combo id value
                               var ComboValue  = comp.getValue();
                                // save data by some Ext.Ajax.request
                                },
                 click: {
                            // you can preload combo store with specifig parameters
                            element: 'el', 
                            fn  : function (store, operation, eOpts) {
                                .....
                                ComboStore.load({
                                        params: {
                                            SomeId : SomeParam
                                        }
                                    });