PDA

View Full Version : Best Practice to Pre-Populate Form from Store in Ext JS 4 MVC



adambuckley
8 Nov 2012, 7:32 PM
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

Ext.application({
name : 'TestApp',
controllers : [ 'TestController' ],


launch : function()
{
appGlobal = this;

Ext.create('Ext.container.Viewport',
{
layout : 'border',
padding : 10,


items : [
{
xtype : 'testView'
} ]
});
}
});



TestController.js

Ext.define('TestApp.controller.TestController',
{
extend : 'Ext.app.Controller',
views : [ 'TestView' ],
stores : [ 'TestStore' ],
models : [ 'TestModel' ]
});



TestModel.js

Ext.define('TestApp.model.TestModel',
{
extend : 'Ext.data.Model',
fields : [ 'id', 'username', 'firstName', 'surname', 'email' ]
});



TestStore.js (will be populated from the server eventually)

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

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);
}
});

vietits
8 Nov 2012, 10:55 PM
With MVC, it's better to move your code to controller instead of leaving it at views:
- Controller


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);
}
}
});
}
});

- View


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);
// }
});

adambuckley
11 Nov 2012, 2:21 PM
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.



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'
}
}
});

adambuckley
11 Nov 2012, 8:40 PM
This is the controller code. The view is populated in the store.load callback - so we know the store has definitely finished loading.


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...
}
});
}
}
});
}
});

adambuckley
12 Nov 2012, 2:43 PM
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

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)

Ext.define('TestApp.view.TestView',
{
extend : 'Ext.form.Panel',
alias : 'widget.testView',
id : 'testView',
title : 'Test Form',
...


TestStore.js

Ext.define('TestApp.store.TestStore',{
extend : 'Ext.data.Store',
model : 'TestApp.model.TestModel',
autoLoad : true,


proxy :
{
type : 'ajax',
url : 'profile.json'
}
});


profile.json (is placed in the same folder as app.js)

{ id : 123,
username : "user",
firstName : "Test",
surname : "User",
email : "testuser@company.com"
}