-
8 Nov 2012 7:32 PM #1
Answered: Best Practice to Pre-Populate Form from Store in Ext JS 4 MVC
Answered: Best Practice to Pre-Populate Form from Store in Ext JS 4 MVC
Hi Folks,
I've spent 3 days trying to produce a form which is pre-populated with data from a Store. I'm using Ext JS 4.1.1 MVC. I've read a whole heap of tutorials, forums posts, eBooks as well as the API.
The following is what I've come up with. It's working correctly at present, but please can some Ext experts tell me if this is the best way of doing things.
Specifically - is my use of afterRender appropriate? Is there any way of setting the value of each form field instead?
Thanks in advance, Adam.
app.js
Code:Ext.application({ name : 'TestApp', controllers : [ 'TestController' ], launch : function() { appGlobal = this; Ext.create('Ext.container.Viewport', { layout : 'border', padding : 10, items : [ { xtype : 'testView' } ] }); } });
TestController.js
Code:Ext.define('TestApp.controller.TestController', { extend : 'Ext.app.Controller', views : [ 'TestView' ], stores : [ 'TestStore' ], models : [ 'TestModel' ] });
TestModel.js
Code:Ext.define('TestApp.model.TestModel', { extend : 'Ext.data.Model', fields : [ 'id', 'username', 'firstName', 'surname', 'email' ] });
TestStore.js (will be populated from the server eventually)
Code:Ext.define('TestApp.store.TestStore', { extend : 'Ext.data.Store', model : 'TestApp.model.TestModel', data : [ { id : '123', username : 'testuser', firstName : 'Test', surname : 'User', email : 'testuser@conexa.com' } ] });
TestView.js
Code:Ext.define('TestApp.view.TestView', { extend : 'Ext.form.Panel', alias : 'widget.testView', title : 'Test Form', bodyPadding : 10, items : [ { name : 'id', xtype : 'displayfield', fieldLabel : 'ID' }, { name : 'firstName', xtype : 'textfield', fieldLabel : 'First Name', allowBlank : false }, { name : 'surname', xtype : 'textfield', fieldLabel : 'Surname', allowBlank : false }, { name : 'email', xtype : 'textfield', fieldLabel : 'Email Address', allowBlank : false, vtype : 'email' } ], afterRender : function() { this.superclass.afterRender.apply(this); var controller = appGlobal.getController('TestController'); var store = controller.getTestStoreStore(); var record = store.first(); this.getForm().loadRecord(record); } });
-
Best Answer Posted by vietits
With MVC, it's better to move your code to controller instead of leaving it at views:
- Controller
- ViewCode:Ext.define('TestApp.controller.TestController', { extend : 'Ext.app.Controller', views : [ 'TestView' ], stores : [ 'TestStore' ], models : [ 'TestModel' ], init: function(){ this.control({ 'testView': { afterrender: function(view){ var store = this.getTestStoreStore(); var record = store.first(); view.getForm().loadRecord(record); } } }); } });
Code:Ext.define('TestApp.view.TestView', { extend : 'Ext.form.Panel', alias : 'widget.testView', title : 'Test Form', bodyPadding : 10, items : [ { name : 'id', xtype : 'displayfield', fieldLabel : 'ID' }, { name : 'firstName', xtype : 'textfield', fieldLabel : 'First Name', allowBlank : false }, { name : 'surname', xtype : 'textfield', fieldLabel : 'Surname', allowBlank : false }, { name : 'email', xtype : 'textfield', fieldLabel : 'Email Address', allowBlank : false, vtype : 'email' } ], // afterRender : function() // { // this.superclass.afterRender.apply(this); // var controller = appGlobal.getController('TestController'); // var store = controller.getTestStoreStore(); // var record = store.first(); // this.getForm().loadRecord(record); // } });
-
8 Nov 2012 10:55 PM #2
With MVC, it's better to move your code to controller instead of leaving it at views:
- Controller
- ViewCode:Ext.define('TestApp.controller.TestController', { extend : 'Ext.app.Controller', views : [ 'TestView' ], stores : [ 'TestStore' ], models : [ 'TestModel' ], init: function(){ this.control({ 'testView': { afterrender: function(view){ var store = this.getTestStoreStore(); var record = store.first(); view.getForm().loadRecord(record); } } }); } });
Code:Ext.define('TestApp.view.TestView', { extend : 'Ext.form.Panel', alias : 'widget.testView', title : 'Test Form', bodyPadding : 10, items : [ { name : 'id', xtype : 'displayfield', fieldLabel : 'ID' }, { name : 'firstName', xtype : 'textfield', fieldLabel : 'First Name', allowBlank : false }, { name : 'surname', xtype : 'textfield', fieldLabel : 'Surname', allowBlank : false }, { name : 'email', xtype : 'textfield', fieldLabel : 'Email Address', allowBlank : false, vtype : 'email' } ], // afterRender : function() // { // this.superclass.afterRender.apply(this); // var controller = appGlobal.getController('TestController'); // var store = controller.getTestStoreStore(); // var record = store.first(); // this.getForm().loadRecord(record); // } });
-
11 Nov 2012 2:21 PM #3
Thanks Vietits
Thanks Vietits
I have now wired my store up to a server as follows.
But the solution shown above is no longer working, because at the time the afterrender is fired, the store has not yet loaded.
How can I wait for the store to load?
Thanks again for your help... Adam.
Code:Ext.define('ProcExt.store.UserProfile', { extend : 'Ext.data.Store', model : 'ProcExt.model.UserProfile', autoLoad : true, proxy : { type : 'rest', url : '/ProcurementServer/profile.json', reader : { type : 'json', root : 'docs', successProperty : 'success' } } });
-
11 Nov 2012 8:40 PM #4
I Think This is How It's Done
I Think This is How It's Done
This is the controller code. The view is populated in the store.load callback - so we know the store has definitely finished loading.
Code:Ext.define('ProcExt.controller.UserProfile',{ extend : 'Ext.app.Controller', views : [ 'TestView' ], stores : [ 'TestStore' ], models : [ 'TestModel' ], init : function() { this.control( { 'testView' : { afterrender : function(view) { var store = this.getTestStoreStore(); store.load(function(records, operation, success) { if(success) { var record = store.first(); view.getForm().loadRecord(record); } else { // TODO: Complain... } }); } } }); } });
-
12 Nov 2012 2:43 PM #5
An Even Better Way
An Even Better Way
I think this is an even better way - set the store autoLoad to true, and write a callback which populates the form when the store has finished loading.
TestController.js
Code:Ext.define('TestApp.controller.TestController',{ extend : 'Ext.app.Controller', views : [ 'TestView' ], stores : [ 'TestStore' ], models : [ 'TestModel' ], init : function() { this.getTestStoreStore().addListener('load', function(store, records, success) { var record = records[0]; var form = Ext.ComponentManager.get('testView'); form.getForm().loadRecord(record); }, this); } });
TestView.js (needs an ID so can be retrieved via Ext.ComponentManager)
Code:Ext.define('TestApp.view.TestView', { extend : 'Ext.form.Panel', alias : 'widget.testView', id : 'testView', title : 'Test Form', ...
TestStore.js
profile.json (is placed in the same folder as app.js)Code:Ext.define('TestApp.store.TestStore',{ extend : 'Ext.data.Store', model : 'TestApp.model.TestModel', autoLoad : true, proxy : { type : 'ajax', url : 'profile.json' } });
Code:{ id : 123, username : "user", firstName : "Test", surname : "User", email : "testuser@company.com" }


Reply With Quote