-
21 Feb 2012 10:43 AM #1
Answered: Model association not working
Answered: Model association not working
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
-
Best Answer Posted by adube
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
Code:... 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
Code: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!
-
21 Feb 2012 11:44 AM #2Sencha - Senior Forum Manager
- Join Date
- Mar 2007
- Location
- St. Louis, MO
- Posts
- 34,107
- Vote Rating
- 453
- Answers
- 3156
Can you post your model here?
Mitchell Simoens @SenchaMitch
Sencha Inc, Senior Forum Manager
________________
http://www.JSONPLint.com - Source to lint your JSONP!
Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
https://github.com/mitchellsimoens
Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/
Need more help with your app? Hire Sencha Services services@sencha.com
Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is almost in print!
When posting code, please use BBCode's CODE tags.
-
21 Feb 2012 11:57 AM #3
Sure. Here goes :
Json
ModelsCode:{ "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" }] } }
Code: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"}} );StoresCode:Ext.define('GeoPrisma.model.Resource', { extend: 'Ext.data.Model', fields: ["config_id", "name", "title", "abstract"], //belongsTo: 'Config' belongsTo: 'GeoPrisma.model.Config' });
Code: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' } } });Code:Ext.define('GeoPrisma.store.Resources', { extend: 'Ext.data.Store', model: "GeoPrisma.model.Resource" });
view.resource.Grid, which is empty
Thanks a lot,Code: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"; } });
Alexandre
-
22 Feb 2012 2:57 AM #4
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.
-
22 Feb 2012 5:20 AM #5
Thanks for your reply.
Okay, let me know if I get this right. When setting
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.Code:store: "Resources"
Alexandre
-
22 Feb 2012 6:04 AM #6
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
Code: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
Code: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
-
22 Feb 2012 11:18 PM #7
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:
Code:... 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.
-
23 Feb 2012 6:10 AM #8
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
Code:... 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
Code: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!
-
23 Feb 2012 11:56 AM #9
Äh okay
.. that should work either...


Reply With Quote