In an Ext JS 4 MVC application I am currently working on, I need to programatically add comboboxes to a form. The list of comboboxes varies depending on the selected user. In addition, the store backing each of the comboboxes is different. Here is my approach.
The Model
In my case, although the stores might have different data, they have the same fields. It is a generic label/value set up.
Ext.define('MyApp.model.LabelValue', { extend: 'Ext.data.Model', fields: [ 'label', 'value' ] });
The Store
Because the stores are so similar for each combo, I created a store that was specific to my case, but generic enough to be used for all the combo boxes. The important part is the alias that is part of the store definition ‘store.mycombostore’. This will allow me to reference the store type, but ensure a new store is created for each combobox. This helpful piece of information is from the comments on the store config for ComboBox, found at Ext.form.field.ComboBox.
Ext.define('MyApp.store.MyComboStore', { extend: 'Ext.data.Store', alias: 'store.mycombostore', model: 'MyApp.model.LabelValue', autoLoad: false, proxy: { type: 'ajax', url : 'put/your/url/here', reader: { type: 'json', root: 'data' } } });
The View
To reduce the amount of remote configuration that I need to generate I defined a custom combobox with all the static configurations that I wanted. I have a few other things going on in my combobox, like using my Remote To Local plugin. I also overrode beforeBlur to allow the user to delete and basically re-empty the combobox, and I’m setting some params before the store loads. I initially listened for the before store load event in the controller after adding the combobox configs to my form, but putting it right in the custom combobox was cleaner. Not sure if it violates MVC or not…
Ext.define('MyApp.view.MyCombo', { extend: 'Ext.form.field.ComboBox', alias: 'widget.mycombo', requires: [ 'MyApp.store.MyComboStore', 'Ext.ux.form.field.RemoteToLocalComboBox' ], allowBlank: true, forceSelection: true, queryMode: 'remote', minChars : 1, //begin query after user types 1 char msgTarget: 'side', queryDelay: 10, triggerAction: 'all', typeAhead: true, typeAheadDelay: 250, labelWidth: 200, width: 450, name: 'roleTemplates', displayField: 'label', valueField: 'value', plugins: [ {ptype:'remotetolocalcombo'} ], beforeBlur: function () { if (this.getRawValue().length === 0) { this.lastSelection = []; } this.doQueryTask.cancel(); this.assertValue(); }, initComponent: function() { var me = this; Ext.applyIf(me, { emptyText: 'Process Access Request...', loadingText: 'Loading...', store: {type: 'roletemplatesremote'} }); me.callParent(arguments); me.getStore().on('beforeload', this.beforeTemplateLoad, this); }, beforeTemplateLoad: function(store) { store.proxy.extraParams = { moduleId: this.moduleId } } });
The Controller
So, in my controller I’m loading all my “user” data to populate the form. As part of my AJAX JSON response, I have the remote configuration:
[ { "xtype":"mycombo", "fieldLabel": "Module One", "moduleId":"module1" }, { "xtype":"mycombo", "fieldLabel": "Module Two", "moduleId":"module2" } ]
And here is the AJAX request and response handling. The Ext.container.Container doc has a section on “Adding via remote configuration” that explains what to do.
Ext.define('MyApp.controller.UserDetail', { //... all the standard controller stuff loadUser: function() { Ext.Ajax.request({ url: 'your/url/here', jsonData: { userId: userId }, scope: this, callback: this.loadUserCallback }); } loadUserCallback: function(options, success, response) { // userDetail is the view where I am adding the comboboxes. The // new comboboxes will be added to a fieldContainer. var userDetail = this.getUserDetail(), responseJson,newCombos; if (success) { responseJson = Ext.decode(response.responseText); if (responseJson.success === true) { try { newCombos = eval(responseJson); userDetail.down('#comboFieldContainer').add(newCombos); } catch (e) { userDetail.down('#comboFieldContainer').add({ xtype: 'component', html:'No pending access requests' }); } } else { // showErrorResults is a function that I have to // display an error message on my view this.showErrorResults(responseJson.message); } } else { // showErrorResults is a function that I have to // display an error message on my view this.showErrorResults('Something went wrong.'); } }, //... });
I have a bit more going on so this is a little stripped down, but looking at the Ext JS docs should clarify what is needed. Basically the AJAX request returns JSON w/the configuration objects. In the response handling, the JSON is eval’d to objects which are then added to the view. By creating a few custom components I am able to dynamically add to objects to my view, without having tons of configuration determined server-side.
Here is a picture. It’s not too exciting, but it’s exactly what I want, two user-specific comboboxes determined server-side at runtime.
Version Info:
Ext JS 4.1.1