0

I am trying to display a property from a JSON received from a server in a combobox within a grid with cell editing. When the user selects an option I want to display the same property, but when the user saves the grid, I want the complete JSON to be sent to the server (not just the display value nor the id field).

This is what I have so far (available here http://jsfiddle.net/apater39/do0xg4r1/):

Ext.define('NS.model.State', {
  extend: 'Ext.data.Model',
  fields: [{
    name: 'id',
    type: 'int'
  }, {
    name: 'name',
    type: 'string'
  }]
});
Ext.define('NS.store.State', {
  extend: 'Ext.data.Store',
  model: 'NS.model.State',
  data: [{
    "id": 1,
    "name": "Alabama"
  }, {
    "id": 2,
    "name": "Alaska"
  }, {
    "id": 3,
    "name": "Arizona"
  }]
});

Ext.define('NS.model.Person', {
  extend: 'Ext.data.Model',
  fields: [{
    name: 'id',
    type: 'int'
  }, {
    name: 'firstName',
    type: 'string'
  }, {
    name: 'state',
    type: 'NS.model.State'
  }]
});

Ext.define('NS.store.Grid', {
  extend: 'Ext.data.Store',
  model: 'NS.model.Person',
  data: {
    'items': [{
      'id': 1,
      "firstName": "Lisa",
      "state": null
    }, {
      'id': 2,
      "firstName": "Bart",
      "state": null
    }, {
      'id': 3,
      "firstName": "Homer",
      "state": null
    }, {
      'id': 4,
      "firstName": "Marge",
      "state": null
    }]
  },
  proxy: {
    type: 'memory',
    reader: {
      type: 'json',
      root: 'items'
    }
  }
});

Ext.create('Ext.grid.Panel', {
  title: 'Simpsons',
  store: Ext.create('NS.store.Grid'),
  columns: [{
    header: 'First Name',
    dataIndex: 'firstName',
    flex: 1,
    editor: 'textfield'
  }, {
    header: 'State',
    dataIndex: 'state',
    flex: 1,
    editor: {
      xtype: 'combobox',
      store: Ext.create('NS.store.State'),
      queryMode: 'local',
      displayField: 'name',
      valueField: 'id'
    }
  }],
  selType: 'cellmodel',
  plugins: [{
    ptype: 'cellediting',
    clicksToEdit: 2
  }],
  height: 150,
  width: 200,
  renderTo: Ext.getBody()
});

If I use valueField 'id' then when the user chooses an option from the combobox the id is displayed (instead of the displayField).

The JSON that I would like to be sent is this:

{
  "id": 1,
  "firstName": "Lisa",
  "state": 
   {
     "id": 1,
     "name": "Alabama"
   }
}

Thanks for the help.

UPDATE:

Based on the suggestion of Jorge Ramon, I arrived at a solution (see http://jsfiddle.net/apater39/8opsqg5s/). The important thing is to to listen to the edit event of cellediting pluging, and then find the selected record of the combo and set the corresponding property.

var gridPanel = Ext.create('Ext.grid.Panel', {
  title: 'Simpsons',
  store: gridStore,
  columns: [{
    header: 'First Name',
    dataIndex: 'firstName',
    flex: 1,
    editor: 'textfield'
  }, {
    header: 'State',
    dataIndex: 'state',
    flex: 1,
    editor: {
      xtype: 'combobox',
      store: Ext.create('NS.store.State'),
      displayField: 'name',
      valueField: 'name',
      editable: false,
      queryMode: 'local',
      forceSelection: true,
      triggerAction: 'all',
      selectOnFocus: true,
      allowBlank: false
    },
    renderer: function(value) {
      return value.name;
    }
  }],
  selType: 'cellmodel',
  plugins: [{
    ptype: 'cellediting',
    clicksToEdit: 2,
    listeners: {
      edit: function(editor, ctx, eOpts) {
        var vendorColIdx = 1;
        if (vendorColIdx === ctx.colIdx) {
          var combo = ctx.grid.columns[vendorColIdx].getEditor(ctx.record);
          var vendorRecord = combo.findRecord('name', ctx.record.get('state'));
          ctx.record.set('state', vendorRecord.data);
        }
        ctx.grid.getStore().sync();
      }
    }
  }],
  height: 250,
  width: 200,
  renderTo: Ext.getBody()
});

The JSON sent becomes:

{"id":1,"firstName":"Lisa","state":{"id":2,"name":"Alaska"}}
antoniojxk
  • 127
  • 2
  • 10
  • If I understand correctly your needs, your problem is that when the save request is sent to the server, it only send the changes and not the full model, is that right? – Psycho Feb 29 '16 at 11:10
  • Hi, that is exactly my problem. In the server side I have a representation of the JSON in Spring (a JSON bean), and it is used both for the get and the save operations. Therefore if the web only sends the id, the request won't conform to the expected format. It will work if at least the web could send an object like {id: 1} for the combobox value. – antoniojxk Feb 29 '16 at 14:10

2 Answers2

2

You will need to change several stuff in your code to achieve want you want to do...

First is that your are trying to work with association (Person contains a State) but you are not declaring the association. To declare your association correctly, I suggest to read this : https://stackoverflow.com/a/16492938/3494608 And also deeply suggest to read this : http://extjs-tutorials.blogspot.fr/2012/05/extjs-hasmany-relationships-rules.html

Afterward, you will need to see how to correctly set your association because your combobox here only set a value (the id of the model corresponding to the select state) and not the record itself.

And then, you will see how to send the complete model with association. I did not did it myself within Ext4.2 but you'll find some lecture in google (Key words: extjs save nested model). Found this first : https://www.sencha.com/forum/showthread.php?274778-Add-new-record-of-Model-that-contains-nested-Model

I don't have a "all-in-one" solution because working with association is unfortunately a though work with ExtJs (less with ExtJs 5+ but still...)

Good luck!

Community
  • 1
  • 1
Psycho
  • 381
  • 1
  • 17
1

You want to have the combo editor set like this example:

editor: {
    xtype: 'combobox',
    store: 'Vendors',
    displayField: 'name',
    valueField: 'name',
    editable: false,
    queryMode: 'remote',
    forceSelection: true,
    triggerAction: 'all',
    selectOnFocus: true,
    allowBlank: false
}

Then, use the celleditor plugin:

plugins: {
   ptype: 'cellediting',
   clicksToEdit: 1,
   listeners: {
       edit: 'onGridEditorEdit'
   }
}

And handle the plugin's edit event:

onGridEditorEdit: function (editor, ctx, eOpts) {
    var vendorColIdx = 2;
    if (vendorColIdx === ctx.colIdx + 1) {
        var combo = ctx.grid.columns[vendorColIdx].getEditor(ctx.record);
        var vendorRecord = combo.findRecord('name', ctx.record.get('vendorName'));
        ctx.record.set('vendorId', vendorRecord.get('id'));
    }
    ctx.grid.getStore().sync();  // Force a post with the updated data.     
}
  • Hi Jorge, thanks for the help. Based on your proposal for the solution I was able to fix the issue. I had to make some tweaks to your proposal. For example, in ctx.record.set I don't get the id field for the combo record but instead I set the record.data. If I don't do that then only the id gets sent to the server. See my solution in (http://jsfiddle.net/apater39/8opsqg5s/) – antoniojxk Mar 06 '16 at 22:53