PDA

View Full Version : Asynchronously load Ext.data.Stores using model association



sskow200
19 May 2011, 6:32 AM
Hello,

I had a question regarding the new core data store. The way the new model architecture is designed it appears that asynchronously loading data stores through the models is a possibility and is in fact a central part of why this architecture was designed this way as this was a large problem in Ext3.x. So I begin with a simple example...

First we create a few models:



Ext.define('My.App.User', {
extend: 'Ext.data.Model',
fields: [
'id',
'name'
],
hasMany: {
model: 'My.App.Friend',
name: 'friends',
associationKey: 'friends'
},
proxy: {
type: 'memory',
reader: 'json',
data: [
{id: 1, name: 'Bob'},
{id: 2, name: 'Joe'},
{id: 3, name: 'Sue'}
]
}
});

Ext.define('My.App.Post', {
extend: 'Ext.data.Model',
fields: [
'id',
'title',
],
hasMany: {
model: 'My.App.Comment',
name: 'comments',
associationKey: 'comments'
},
proxy: {
type: 'memory',
reader: 'json',
data: [
{id: 1, title: 'My First Post'},
{id: 2, title: 'My Second Post'},
{id: 3, title: 'My Third Post'}
]
}
});
Ext.define('My.App.Comment', {
extend: 'Ext.data.Model',
fields: [
'id',
'user_id',
'date',
'comment'
],
proxy: {
type: 'memory',
reader: 'json',
data: [
{id: 1, user_id: 1, date: '05/19/2011', comment: 'Simple Comment 1'},
{id: 2, user_id: 2, date: '05/19/2011', comment: 'Simple Comment 2'},
{id: 3, user_id: 3, date: '05/19/2011', comment: 'Simple Comment 3'},
]

}
});




Browsing through the minimal documentation on this topic, in order to view all of this data it seems to be needed all in the initial query. However, my thinking on this would be to only load this data when we want/need it. Like so,




//this will give me all the available users
var users = Ext.data.Store({model: 'My.App.User', autoLoad: true});

...some operations...

//after some operations, then load ALL posts
var posts = users.posts().load();

...some operations...

//after some more operations, then load ALL comments
var comments = posts.comments().load();



Unfortunately, this does not work like you would expect it to and the data is not actually accessible from the stores that are dynamically created. However, the data is accessible via the proxy where the data resides, and even using a REST proxy the request is made to the server. The issue here is that when you try to extra the data directly from the store via: posts.data.items or posts.each() the data has not be placed in the proper place. My thinking there maybe was a property or config that would handle this for you such as autoLoad: true on the associated models to no avail. I even added an extra config in the hasMany config using storeConfig: {autoLoad: true} with the same result. Maybe I am just missing something regarding this issue. One might say, "why don't you just access the data directly in the proxy?" and as well that is all fine, it seems to me that the best way to want to access this data is from the store directly as to not disrupt the read/write communication between the store and the proxy. If anyone could shed some light on this subject that would be much appreciated. Thank you

jenjenut233
23 May 2011, 1:30 PM
Association data belongs to a record, not a store, so the helpful dynamic store creation methods are specific to an individual store item. By declaring 'users' as a store and then saying users.posts(), you're not telling Sencha what data you want since the 'users' store has no concept of posts. Rather, you need to either grab a specific user then request its posts, or just create a posts store that gets loaded independent of a user. That's pretty basic model structure, not specific to Sencha.


posts = new Ext.data.Store({ model: 'Post' });
posts.load();

OR


users = new Ext.data.Store({ model: 'User' });
user = users.getAt(0);
user.posts.load();

sskow200
23 May 2011, 2:36 PM
Thanks for your reply. I have in fact done exactly what you are implying already. However, the only way the records truly load is if you get the 'posts' on the original data query. The way the Sencha docs are explaining it the data must come through like this:



data: {
users: [
{
id: 1,
name: 'Joe',
posts: [
{
id: 1,
user_id: 1,
comment: 'Some Post Data'
},{
id: 2,
user_id: 1,
comment: 'Some More Post Data'
}
]
}
]
}


Doing it this way in fact does work, however, the 'Posts' are required within the initial data. I want my initial query to only look like this:



data: {
users: [
{
id: 1,
name: 'Joe'
}
]
}


And (assuming the users store is already loaded) if I call:



var user = users.getAt(0),
posts = user.posts();


The post data should be retrieved here using the proxy provided in the Posts model. This is not in fact what happens and the post data is blank. However, the post data can be viewed inside the proxy so it is half working. It is my belief that because the data was not initially loaded in the top-most store, you can not access it from here. You have to manually access it via:



users.posts().proxy.data


Doing it this way is not desirable unfortunately so I am looking for a complete approach. If this is confusing I'll try to give a better example with documentation perhaps. For now, I have foregone the dynamic loading and just have all the data in the initial query until I have a better solution.

jenjenut233
24 May 2011, 9:56 AM
Ah, I also ran into that issue.. I had to add remoteFilter: true on the storeConfig property in the hasMany association, like so:


Ext.regModel('MessageThread', {
fields: ['id', 'subject', 'message_count', 'last_sender', 'date', 'thread'],
proxy: {
type : 'rest',
url : '/js_client/message_threads',
format: 'json',
reader: {
record: 'thread'
}
},
hasMany: { model: 'Message', name: 'messages', filterProperty: 'thread', foreignKey: 'thread', storeConfig: { remoteFilter: true } }
});

Before adding the remoteFilter option, I noticed the rawData appeared in the proxy, but calling store.data resulted in an empty collection. After adding that, the data populates correctly. This isn't documented and it took me awhile to figure it out. Hope it helps.