PDA

View Full Version : Model association not working



adube
21 Feb 2012, 10:43 AM
Hi,

I'm new with Ext JS 4.0. After reading the Data and MVC documentation, I'm now trying it out for the first time. I'm having currently having issues with the model association.

My use-case is as follow : a Config hasMany Resources, a Resource belongsTo a Config. I currently use a static JSON of what I expect my server to output for a "getConfig" request, which should return a single "config" element with a "resources" array parameter. My problem is that I expect the config.resources() method to exists and it doesn't or have a records[0].data.resources parameter set but it's not.

Here's a complete and very simple live demo demonstrating my issue. I have a view.resource.Grid object I expect to have the 2 resources elements read from the JSON file displayed, but they're not.

http://dev8.mapgears.com/extjs4-association/

What am I doing wrong ?

Many thanks,

Alexandre

mitchellsimoens
21 Feb 2012, 11:44 AM
Can you post your model here?

adube
21 Feb 2012, 11:57 AM
Sure. Here goes :

Json


{
"success": true,
"config": {
"id": 1,
"resources": [{
"name": "R_OSM",
"title": "OpenStreetMap",
"abstract": "This is the OpenStreetMap resource"
}, {
"name": "R_Countries_Population",
"title": "Countries Population",
"abstract": "Custom countries population points"
}]
}
}


Models


Ext.define('GeoPrisma.model.Config', {
extend: 'Ext.data.Model', requires: [
'GeoPrisma.model.Resource',
'Ext.data.HasManyAssociation',
'Ext.data.BelongsToAssociation'
],
fields: ["id"],

//hasMany: {model: "Resource", name: "resources"}
hasMany: {model: "GeoPrisma.model.Resource", name: "resources"}}
);




Ext.define('GeoPrisma.model.Resource', {
extend: 'Ext.data.Model',
fields: ["config_id", "name", "title", "abstract"],
//belongsTo: 'Config'
belongsTo: 'GeoPrisma.model.Config'
});


Stores


Ext.define('GeoPrisma.store.Config', {
extend: 'Ext.data.Store',
model: "GeoPrisma.model.Config",
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data/config.json',
reader: {
type: 'json',
root: 'config',
successProperty: 'success'
}
}
});




Ext.define('GeoPrisma.store.Resources', {
extend: 'Ext.data.Store',
model: "GeoPrisma.model.Resource"
});


view.resource.Grid?, which is empty


Ext.define('GeoPrisma.view.resource.Grid' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.resourcegrid',
title : 'Resources Grid',
//store: 'GeoPrisma.store.Resources',
store: 'Resources',
width: 400,
height: 200,
border: true,
initComponent: function() {
console.log('initComponent GeoPrisma.view.resource.Grid');
this.columns = [
{header: 'Name', dataIndex: 'name', flex: 1},
{header: 'Title', dataIndex: 'title', flex: 1},
{header: 'Abstract', dataIndex: 'abstract', flex: 1}
];
this.callParent(arguments);
var foo = "bar";
}
});


Thanks a lot,

Alexandre

börn
22 Feb 2012, 2:57 AM
Your grid should have it's store config set to yourLoadedRecord.resources()... maybe there is a timing problem.. try to play with the loaded model and it's associations in the console. You may consider using reconfigure in your grid after your model is successfully loaded.

adube
22 Feb 2012, 5:20 AM
Thanks for your reply.

Okay, let me know if I get this right. When setting


store: "Resources"

inside the view.resource.Grid, it creates a store.Resources but it's not the same instance as the store.Resources the Config record has.

Alexandre

adube
22 Feb 2012, 6:04 AM
Hi,

I made some modifications following that logic. Now I can see the resourcesStore property inside the config record and it has 2 resource records.

Next step, bind this store to my grid. In the controller, I get the grid using the getResourceGridView() then expect to be able to use the reconfigure() method, but the object returned is not an instance of a Ext.grid.Panel.

What is the correct way to bind the store to the grid and how to get it ?

I updated the online sample at http://dev8.mapgears.com/extjs4-association/. Here's also a copy of the controller I use and the console log.

Thanks,

Alexandre

?Controller


Ext.define('GeoPrisma.controller.Config', {
extend: 'Ext.app.Controller',


stores: [
"Config",
"Resources"
],


models: [
"Config"//,
//"Resource"
],


views: [
'resource.Grid'
],


init: function() {
console.log('Initialized Configs Controller!');
var me = this;


me.getConfigStore().on({
scope: me,
load : me.onConfigStoreLoad
});
},


onLaunch: function() {
var foo = "bar";
},


onConfigStoreLoad: function(store, records) {
var foo = "bar";
console.log('Config store loaded with '+records.length+' record(s).');


if (records.length && records[0] && records[0].resourcesStore) {
console.log(
'Config store has a resourcesStore with '+
records[0].resourcesStore.data.length +
' record(s)'
);


// check if resourceGridView is a Ext.grid.Panel
var grid = this.getResourceGridView();
var isGrid = (grid instanceof Ext.grid.Panel);


// console log for isGrid
var msg = [];
msg.push(grid.getName() + ' is ');
!isGrid && msg.push('not ');
msg.push('an instance of Ext.grid.Panel');
console.log(msg.join(""));


// reconfigure if isGrid
isGrid && grid.reconfigure(records[0].resourcesStore)
}
}
});



Console Log


Initialized Configs Controller!
initComponent GeoPrisma.view.resource.Grid
Config store loaded with 1 record(s)
Config store has a resourcesStore with 2 record(s)
GeoPrisma.view.resource.Grid is not an instance of Ext.grid.Panel

börn
22 Feb 2012, 11:18 PM
I think the store load is to early for calling reconfigure. The deal with reconfigure is to put a new store and new columns to a grid, which is allready there. If you are in your init-processing of the controller this isn't the case. I configured a onRender Function in my controller where i call the grid with reconfigure.. i think your
this.getResourceGridView() call only gets you a pointer to the constructor of your grid-panel so this wouldn't be a reference to the view and therefor not an instanceof a grid.

I suggest something like this in your controller:



...

init: function() {


this.control('yourgridxtype': {
'afterrender' : this.reconfigureView
}
,this);


},

reconfigureView: function(grid) {

grid.reconfigure(this.getStore()); //don't know wether you have to deal with the columns... i do, 2nd parameter

}




But this is how i do that - and this is mainly because I'm also configuring my grid with some kind of metadata sent by the server to adjust columsn and stuff. If you have something more ungeneric you should be able to achieve your goals in a more simple way, only by adding the store of the model to the grid maybe in your init processing. And then overwrite a initComponent function in your grid-view and setting the given store of the model in it.

adube
23 Feb 2012, 6:10 AM
Thanks to you börn, I finally got it working. It was a combination of the two ways actually.

On grid 'afterrender', I can get a hold on the grid instance, but the configStore hasn't been loaded yet at that point, thus resulting in not having the configStore.records[0].data.resourcesStore created. That means I still need to listen to the configStore 'load' event. By keeping the grid instance as a private property of the controller, I'm able to use it in the store 'load' callback.

I updated the online sample. Here's how it looks now :

controller.Config portion


...
init: function() {
console.log('Initialized Configs Controller!');
var me = this;


me.getConfigStore().on({
scope: me,
load : me.onConfigStoreLoad
});


this.control({
'resourcegrid': {
'afterrender': this.onResourceGridAfterRender
}
}, this);
},


onLaunch: function() {
var foo = "bar";
},


onResourceGridAfterRender: function(grid, options) {
console.log('resourcegrid afterrender fired!');
this.resourceGrid = grid;
},


onConfigStoreLoad: function(store, records) {
console.log('Config store loaded with '+records.length+' record(s).');


if (records.length && records[0] && records[0].resourcesStore &&
this.resourceGrid
) {
console.log(
'Config store has a resourcesStore with '+
records[0].resourcesStore.data.length +
' record(s), reconfiguring resourceGrid!'
);
this.resourceGrid.reconfigure(records[0].resourcesStore)
}
}
...


Console log


Initialized Configs Controller!
initComponent GeoPrisma.view.resource.Grid
resourcegrid afterrender fired!
Config store loaded with 1 record(s).
Config store has a resourcesStore with 2 record(s), reconfiguring resourceGrid!

börn
23 Feb 2012, 11:56 AM
Äh okay ;) .. that should work either...