- Always put your Proxies in your Models, not your Stores, unless you have a very good reason not to *
- Always require your child models if using them in hasMany relationships. **
- Always use foreignKey if you want to load the children at will
- Always use associationKey if you return the children in the same response as the parent
- You can use both foreignKey and associationKey if you like
- Always name your hasMany relationships
- Always use fully qualified model names in your hasMany relationship
- Consider giving the reader root a meaningful name (other than "data")
- The child model does not need a belongsTo relationship for the hasMany to work
Example:
Ext.define('Assoc.model.Contact', { extend:'Ext.data.Model', requires:[ 'Assoc.model.PhoneNumber' /* rule 2 */ ], fields:[ 'name' /* id field is inherited from Ext.data.Model */ ], hasMany:[ { foreignKey: 'contact_id', /* rule 3, 5 */ associationKey: 'phoneNumbers', /* rule 4, 5 */ name: 'phoneNumbers', /* rule 6 */ model: 'Assoc.model.PhoneNumber' /* rule 7 */
} ], proxy:{ /* rule 1 */ type: 'ajax', url: 'assoc/data/contacts.json', reader: { type: 'json', root: 'contacts' /* rule 8 */ } } }); // example usage: var c = new Assoc.model.Contact({id:99}); /* * assuming that PhoneNumber.proxy is AJAX and has a url set to 'phonenumbers', the below function would make an http request like this: * /phonenumbers?page=1&start=0&limit=25&filter=[{"property":"contact_id","value":"99"}] * ie, it would make a request for all phone numbers, but ask the server to filter them by the contact_id of the Contact, which is 99 in this case */ c.phoneNumbers().load();
* The store will inherit its model's proxy, and you can always override it
** To make it easy, and avoid potential circular references, you can require them in app.js .
works ok, without proxy in model.
ReplyDeleteits stupid to bind model to proxy, why would you use MVC then at all?
1. Be polite and kind or I will ban you.
Delete2. It's easier to load a single record if the proxy is on the model
3. The store inherits the model's proxy, and you can always override it.
4. If you have two stores that use the same model, you are duplicating code by putting the same proxy in both stores.
5. Whether a proxy is on a model or on a list of models (a store) has absolutely nothing to do with MVC.
ban anonymous?
ReplyDelete2. its easier, its wrong pattern.
Why - not composable.
You mixing concerns and putting too much knowledge into data representation.
Representation and operation/action - different things.
3.4. You mixing causality here.
Its not model responsibility - it responsibility of dependency resolver to inject right Proxy. Proxy should be injectable as a dependency.
5. Really?
Let say like this, i enjoy your blog for ExtJS gritty nitty details.
But its pitty that extjs mvc community does not have any strong OOP evangelists, and that's why this framework has so messy details leaking all over the place.
And that's the reason i need those nitty gritty details. Sigh.
In this regard i recommend to see the reasoning behind mvvm.
I am receiving json data where each "entity" is the same and it contains a type to differentiate them, because some are children of others. For that reason each entity also holds a collection of its children as a string formed with comma separated ids to the children.
DeleteI need to build a panel with some rectangles at each of the 3 levels, representing the entities at each level.
How would any of you attack this challenge?
p.s. your blog is still awesome, and no offense meant to you personally.
ReplyDeleteExtJs inconsistency just pissing me off.
As an example - assigning rootNode to 'Ext.tree.Panel' works differently for node from treeStore vs Store.
Moreover, events not getting relayed in treeStore case back into store.
treePanel.getView().setRootNode(treeStore.getRootNode());
versus
treePanel.setRootNode(store.getRootNode());
I hear what you are saying. They are sort of using the ActiveRecord pattern with their models and proxies. I think it would be better with a DataMapper style pattern (with a different class to load and save models), but that's what we have.
ReplyDeleteIt's not a perfect library, that's for sure. But it's better than the rest, AFAIC.
Seems to me too.
ReplyDeleteI looked through several frameworks, but ExtJS has the most mature controls.
http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/
Though the price of inconsistencies is high as well.
I get around in my opinion bad MVC design decisions (especially in model/store part being tied to view) though using Joose, Rx.
So far good, but lots of fixture code.
Hi, I saw your JSFiddle example regarding nested XML here:
ReplyDeletehttp://jsfiddle.net/el_chief/668Fg/5/
I'm working with a nested data example as well, but the data is a little different. Keeping the data consistent with the JSFiddle example, how would you set up the associations if the address tags were not wrapped by tags? That's the data I have to work with in my current scenario and I'm having trouble finding an example of how to set that sort of association up.
EDIT: that should have read .... if the address tags were not wrapped by addressList tags.
DeleteI believe you can use an array operator to access elements as well. Also, check out the convert function of the data field class.
DeleteExtjs means nothing, say which version of JS are your posts for.
ReplyDeleteYou should use Proxies in Stores, as they seems to use in Sencha Architect since this is the way they want to do it.
Ext.define('MyApp.store.Whatever', {
extend: 'Ext.data.Store',
alias: 'store.whatever',
requires: [
'MyApp.model.Whatever'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
storeId: 'Whatever',
model: 'MyApp.model.Whatever',
proxy: {
type: 'ajax',
url: 'http://localhost/sandbox/users.json',
reader: {
type: 'json',
root: 'root'
}
}
}, cfg)]);
}
});
Regards
How do you create and save a single model if the proxy is in the store?
DeleteWhy put the proxy in the store, when it automatically inherit's its model's proxy anyways?
Sencha courses teach you to use proxies in models. That way it can be used for one or more records (ask neil said).
DeleteOne reason to put proxy in store is when more than one store uses same model, but different proxy (aka local storage vs jsonp) or proxy settings (aka url).
proxy in model... very bad design
ReplyDeleteIt's called ActiveRecord, promoted by Martin Fowler, used by Ruby on Rails, Spring Roo, and is perfectly acceptable. If you want to put a post on your blog showing how DataMapper is demonstrably better, please post a link :)
DeleteRather than hollow criticism "very bad design"; it will be more useful to provide constructive criticism i.e provide a "better example".
DeleteHi, I am little confused..here, and I am new in extjs.
ReplyDeleteyou have only name in contact and written contact_id as foreign key in hasMany..and as u have mentioned that id is inherited from Ext.app.Model. so,
is it like that it takes name contact and id and combined that as contact_id in foreign key ?
and what is root in it ?
Thanks :)
There are two models, contact and phone_number, though I didn't get into the definition of phone_number. The models look like this:
DeleteCONTACT
id
name
PHONE
id
contact_id
number
it violates SRP
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThere are a couple of reasons why I think defining proxies inside your model is NOT bad design. Aside from the reasons mentioned by Neil repeatedly, remember that we are leaving proxy *configuration* inside the model, not actual logic. What the ExtJs source is doing it is nothing of our concern (though reading the source is a great way to understand ExtJs better).
ReplyDeleteFurthermore, remember this is javascript, not Java or C#. Over-engineering things like this will just make things harder and bloat your code.
Now if having your proxy inside the model actually gives you troubles, that's a complete story. But I doubt it will.
Take a look at this guide...
ReplyDeletehttp://docs.sencha.com/extjs/4.2.0/#/guide/data
RobertoM
Is it possible to specify configuration options for autogenerated store?
ReplyDeleteI mean, for example, how to set config options like autoSync, autoDestroy for store, returned by c.phoneNumbers()
Yes, you can add a storeConfig:{...} property to the hasMany relationship to setup the store.
DeleteI have the same problem, but your solution doesn't work for me...
ReplyDeleteSee my post..
http://www.sencha.com/forum/showthread.php?268099-Children-elements-aren-t-show-using-nested-json-Model-and-hasMany-association.
Can you help me?
I understand you people about putting the proxy configuration in the store and not in the model but I also got the point of Neil regarding this one.
ReplyDeleteActually you can't compare it how Sencha Architect want to do it, there are lots of ways on how to apply it in Sencha you just choose what you prefer.
I have a query on this one..
ReplyDelete/phonenumbers?page=1&start=0&limit=25&filter=[{"property":"contact_id","value":"99"}]
The problem is that we don't have filter query on our API, but I can get the child use the ID like
/endpoint/contacts/[contactid]/phonenumbers
What do you think of this implementation?
I commonly reference this post when answering questions on StackOverflow, just figured I'd pop in here and say "Thanks" as well as "Good job!" :) I just wrote up a (rather long) blog post on ExtJS associations and linked to you as an awesome reference: http://codingishard.com/2013/08/29/extjs-associations-the-good-the-bad-and-the-ugly/
ReplyDeleteHi could you please tell me how we can filter hasMany data in memory proxy store.? here is my response
ReplyDeleteroutes: [
{
cdcName: "-----",
routeID: -----,
routeName: "------",
stores: [
{
storeAddress: "-----",
storeCity: "-------",
storeEmailAddress: "--------",
storeID: ---
},
{
},
and so on ....
Ext.define('Pro.model.Route', {
extend: 'Ext.data.Model',
fields: [
{
name: 'routeID',
dataType: 'int',
optional: false
},
{
name: 'cdcName',
dataType: 'string',
optional: false
},
{
name: 'routeName',
dataType: 'string',
optional: false
},'stores'
],
associations: {
type: 'hasMany',
model: 'Pro.model.Store',
name:'stores',
associationKey: 'stores'
}
});
i am able to filter record on the basis of cdcName , routeName but i am not able to filter record on the basis of storeID
please tell me . Thanks
Hi,
DeleteI have a similar issue as Humayun Javed ^^. How do I filter a grid containing columns from both models, in a similar hasMany association scenario like he describes
Hi,
DeleteI have a similar issue as Humayun Javed ^^. How do I filter a grid containing columns from both models, in a similar hasMany association scenario like he describes
Codeureka.com offers customized onsite Online Training Mobile Application Development for iOS application development for iPhone and iPad Using Objective-C.
ReplyDeleteThanks and that i have a nifty provide: Whole Home Renovation Cost contractors near me for home renovation
ReplyDelete