extjsextjs5roweditor

ExtJS 5: Complex grid data - set column editor value


I have "complex" data--meaning there are associations in my data--and I'm trying to use these associations in my grid. I create the columns based on some of the data, and because the data is nested in an array, I set a renderer for each column... I also set an editor. The renderer is working just fine, but setting the editor's value is not working out like I thought it would. Here's my code (and Fiddle):

Ext.application({
  name : 'Fiddle',
  launch : function() {
    Ext.define('Phone', {
      extend: 'Ext.data.Model',
      fields: [
        {name: 'phone', type: 'int'},
        {name: 'type', type: 'string'}
      ]
    });
    Ext.define('Person', {
      extend: 'Ext.data.Model',
      fields: [
        {name: 'name', type: 'string'}
      ],
      hasMany: [
        {associationKey: 'phones', model: 'Phone', name: 'getPhonesStore'}
      ]
    });
    var beforeEdit = function(editor, context, eOpts) {
      var grid = context.grid;
      var record = context.record;
      if (grid && record) {
          var phonesStore = record.getPhonesStore();
          var columns = grid.columns;
          if (columns && phonesStore) {
              for (var i = 1; i < columns.length; i++) {
                  var column = columns[i];
                  if (column) {
                      var editor = column.getEditor();
                      if (editor) {
                          alert(phonesStore.getAt(i - 1).get('phone'));
                          editor.setValue(phonesStore.getAt(i - 1).get('phone'));
                      }
                  }
              }
          }
      }
    };
    Ext.define('MyView', {
      extend: 'Ext.grid.Panel',
      store: Ext.create('Ext.data.Store', {
        model: 'Person',
        proxy: {
          type: 'memory'
        },
        data: [
          {name: 'blah', phones: [{phone: 123456789, type: 'Home'}, {phone: 9999999999, type: 'Cell'}]},
          {name: 'bleh', phones: [{phone: 222222222, type: 'Home'}, {phone: 1111111111, type: 'Cell'}]}
        ]
      }),
      plugins: [
        {ptype: 'rowediting', clicksToEdit: 1, listeners: {beforeedit: beforeEdit}}
      ],
      height: 300,
      width: 400,
      initComponent: function() {
        var store = this.getStore();
        if (store) {
          var firstRecord = store.first();
          if (firstRecord) {
            var phonesStore = firstRecord.getPhonesStore();
            if (phonesStore) {
              var columns = [{
                xtype: 'gridcolumn',
                dataIndex: 'name',
                text: 'Name',
                editor: {
                  xtype: 'textfield',
                  hideTrigger: true
                }
              }];
              phonesStore.each(function(phoneRec) {
                columns.push({
                  xtype: 'gridcolumn',
                  text: phoneRec.get('type'),
                  renderer: this.phoneRenderer,
                  editor: {
                    xtype: 'numberfield',
                    hideTrigger: true
                  }
                });
              }, this);
              this.columns = columns;
            }
          }
        }
        this.callParent();
      },
      phoneRenderer: function(value, metaData, record, rowIndex, colIndex) {
        return record.getPhonesStore().getAt(colIndex - 1).get('phone');
      }
    });
    Ext.create('MyView', {
      renderTo: Ext.getBody()
    });
  }
});

In total, I have 3 columns... Name, Home, and Cell. Now you might be thinking, why don't I just have a Cell and Home object instead of the phones array... well, that's not what I'm looking to do, as I don't think that's how to properly structure this data. Anyway, I create these two extra columns when I init my grid.

The problem comes with the editor that I set for the "Home" and "Cell" columns... because I'm using nested data and don't have a proper dataIndex, when the editor renders, it has an empty value for the editor. So I figured try tapping into the beforeedit event, and I can get my values, but unfortunately, it doesn't look like I can set the editor's value, as I'm assuming the startEdit method has some trickery going on.

You'll see that when you click on a row, it alerts the Home and Cell values that I want to set in their editors, but using setValue for the editor doesn't work... does anyone have any insight on how to get this going?


Solution

  • I was able to solve this by using the setEditor method (on the column) when the row is clicked:

    Ext.application({
      name : 'Fiddle',
      launch : function() {
        Ext.define('Phone', {
          extend: 'Ext.data.Model',
          fields: [
            {name: 'phone', type: 'int'},
            {name: 'type', type: 'string'}
          ]
        });
        Ext.define('Person', {
          extend: 'Ext.data.Model',
          fields: [
            {name: 'name', type: 'string'}
          ],
          hasMany: [
            {associationKey: 'phones', model: 'Phone', name: 'getPhonesStore'}
          ]
        });
        var beforeEdit = function(editor, context, eOpts) {
          var grid = context.grid;
          var record = context.record;
          if (grid && record) {
              var phonesStore = record.getPhonesStore();
              var columns = grid.getView().getGridColumns();
              if (columns && phonesStore) {
                  for (var i = 1; i < columns.length; i++) {
                      var column = columns[i];
                      if (column) {
                          column.setEditor({
                              xtype: 'numberfield',
                              hideTrigger: true,
                              value: phonesStore.getAt(i - 1).get('phone')
                          });
                      }
                  }
              }
          }
        };
        Ext.define('MyView', {
          extend: 'Ext.grid.Panel',
          store: Ext.create('Ext.data.Store', {
            model: 'Person',
            proxy: {
              type: 'memory'
            },
            data: [
              {name: 'blah', phones: [{phone: 123456789, type: 'Home'}, {phone: 9999999999, type: 'Cell'}]},
              {name: 'bleh', phones: [{phone: 222222222, type: 'Home'}, {phone: 1111111111, type: 'Cell'}]}
            ]
          }),
          plugins: [
            {ptype: 'rowediting', clicksToEdit: 1, listeners: {beforeedit: beforeEdit}}
          ],
          height: 300,
          width: 400,
          initComponent: function() {
            var store = this.getStore();
            if (store) {
              var firstRecord = store.first();
              if (firstRecord) {
                var phonesStore = firstRecord.getPhonesStore();
                if (phonesStore) {
                  var columns = [{
                    xtype: 'gridcolumn',
                    dataIndex: 'name',
                    text: 'Name'
                  }];
                  phonesStore.each(function(phoneRec) {
                    columns.push({
                      xtype: 'gridcolumn',
                      text: phoneRec.get('type'),
                      renderer: this.phoneRenderer
                    });
                  }, this);
                  this.columns = columns;
                }
              }
            }
            this.callParent();
          },
          phoneRenderer: function(value, metaData, record, rowIndex, colIndex) {
            return record.getPhonesStore().getAt(colIndex - 1).get('phone');
          }
        });
        Ext.create('MyView', {
          renderTo: Ext.getBody()
        });
      }
    });