1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-data.HasManyAssociation'>/**
2 </span> * @author Ed Spencer
3 * @class Ext.data.HasManyAssociation
4 * @extends Ext.data.Association
6 * <p>Represents a one-to-many relationship between two models. Usually created indirectly via a model definition:</p>
8 <pre><code>
9 Ext.define('Product', {
10 extend: 'Ext.data.Model',
12 {name: 'id', type: 'int'},
13 {name: 'user_id', type: 'int'},
14 {name: 'name', type: 'string'}
19 extend: 'Ext.data.Model',
21 {name: 'id', type: 'int'},
22 {name: 'name', type: 'string'}
24 // we can use the hasMany shortcut on the model to create a hasMany association
25 hasMany: {model: 'Product', name: 'products'}
27 </pre></code>
29 * <p>Above we created Product and User models, and linked them by saying that a User hasMany Products. This gives
30 * us a new function on every User instance, in this case the function is called 'products' because that is the name
31 * we specified in the association configuration above.</p>
33 * <p>This new function returns a specialized {@link Ext.data.Store Store} which is automatically filtered to load
34 * only Products for the given model instance:</p>
36 <pre><code>
37 //first, we load up a User with id of 1
38 var user = Ext.ModelManager.create({id: 1, name: 'Ed'}, 'User');
40 //the user.products function was created automatically by the association and returns a {@link Ext.data.Store Store}
41 //the created store is automatically scoped to the set of Products for the User with id of 1
42 var products = user.products();
44 //we still have all of the usual Store functions, for example it's easy to add a Product for this User
46 name: 'Another Product'
49 //saves the changes to the store - this automatically sets the new Product's user_id to 1 before saving
51 </code></pre>
53 * <p>The new Store is only instantiated the first time you call products() to conserve memory and processing time,
54 * though calling products() a second time returns the same store instance.</p>
56 * <p><u>Custom filtering</u></p>
58 * <p>The Store is automatically furnished with a filter - by default this filter tells the store to only return
59 * records where the associated model's foreign key matches the owner model's primary key. For example, if a User
60 * with ID = 100 hasMany Products, the filter loads only Products with user_id == 100.</p>
62 * <p>Sometimes we want to filter by another field - for example in the case of a Twitter search application we may
63 * have models for Search and Tweet:</p>
65 <pre><code>
66 Ext.define('Search', {
67 extend: 'Ext.data.Model',
75 filterProperty: 'query'
80 extend: 'Ext.data.Model',
82 'id', 'text', 'from_user'
86 //returns a Store filtered by the filterProperty
87 var store = new Search({query: 'Sencha Touch'}).tweets();
88 </code></pre>
90 * <p>The tweets association above is filtered by the query property by setting the {@link #filterProperty}, and is
91 * equivalent to this:</p>
93 <pre><code>
94 var store = new Ext.data.Store({
99 value : 'Sencha Touch'
103 </code></pre>
105 Ext.define('Ext.data.HasManyAssociation', {
106 extend: 'Ext.data.Association',
107 requires: ['Ext.util.Inflector'],
109 alias: 'association.hasmany',
111 <span id='Ext-data.HasManyAssociation-cfg-foreignKey'> /**
112 </span> * @cfg {String} foreignKey The name of the foreign key on the associated model that links it to the owner
113 * model. Defaults to the lowercased name of the owner model plus "_id", e.g. an association with a where a
114 * model called Group hasMany Users would create 'group_id' as the foreign key. When the remote store is loaded,
115 * the store is automatically filtered so that only records with a matching foreign key are included in the
116 * resulting child store. This can be overridden by specifying the {@link #filterProperty}.
117 * <pre><code>
118 Ext.define('Group', {
119 extend: 'Ext.data.Model',
120 fields: ['id', 'name'],
125 extend: 'Ext.data.Model',
126 fields: ['id', 'name', 'group_id'], // refers to the id of the group that this user belongs to
129 * </code></pre>
132 <span id='Ext-data.HasManyAssociation-cfg-name'> /**
133 </span> * @cfg {String} name The name of the function to create on the owner model to retrieve the child store.
134 * If not specified, the pluralized name of the child model is used.
135 * <pre><code>
136 // This will create a users() method on any Group model instance
137 Ext.define('Group', {
138 extend: 'Ext.data.Model',
139 fields: ['id', 'name'],
142 var group = new Group();
143 console.log(group.users());
145 // The method to retrieve the users will now be getUserList
146 Ext.define('Group', {
147 extend: 'Ext.data.Model',
148 fields: ['id', 'name'],
149 hasMany: {model: 'User', name: 'getUserList'}
151 var group = new Group();
152 console.log(group.getUserList());
153 * </code></pre>
156 <span id='Ext-data.HasManyAssociation-cfg-storeConfig'> /**
157 </span> * @cfg {Object} storeConfig Optional configuration object that will be passed to the generated Store. Defaults to
161 <span id='Ext-data.HasManyAssociation-cfg-filterProperty'> /**
162 </span> * @cfg {String} filterProperty Optionally overrides the default filter that is set up on the associated Store. If
163 * this is not set, a filter is automatically created which filters the association based on the configured
164 * {@link #foreignKey}. See intro docs for more details. Defaults to undefined
167 <span id='Ext-data.HasManyAssociation-cfg-autoLoad'> /**
168 </span> * @cfg {Boolean} autoLoad True to automatically load the related store from a remote source when instantiated.
169 * Defaults to <tt>false</tt>.
172 <span id='Ext-data.HasManyAssociation-cfg-type'> /**
173 </span> * @cfg {String} type The type configuration can be used when creating associations using a configuration object.
174 * Use 'hasMany' to create a HasManyAssocation
175 * <pre><code>
180 * </code></pre>
183 constructor: function(config) {
188 me.callParent(arguments);
190 me.name = me.name || Ext.util.Inflector.pluralize(me.associatedName.toLowerCase());
192 ownerProto = me.ownerModel.prototype;
196 storeName : name + "Store",
197 foreignKey: me.ownerName.toLowerCase() + "_id"
200 ownerProto[name] = me.createStore();
203 <span id='Ext-data.HasManyAssociation-method-createStore'> /**
205 * Creates a function that returns an Ext.data.Store which is configured to load a set of data filtered
206 * by the owner model's primary key - e.g. in a hasMany association where Group hasMany Users, this function
207 * returns a Store configured to return the filtered set of a single Group's Users.
208 * @return {Function} The store-generating function
210 createStore: function() {
212 associatedModel = that.associatedModel,
213 storeName = that.storeName,
214 foreignKey = that.foreignKey,
215 primaryKey = that.primaryKey,
216 filterProperty = that.filterProperty,
217 autoLoad = that.autoLoad,
218 storeConfig = that.storeConfig || {};
225 if (me[storeName] === undefined) {
226 if (filterProperty) {
228 property : filterProperty,
229 value : me.get(filterProperty),
234 property : foreignKey,
235 value : me.get(primaryKey),
240 modelDefaults[foreignKey] = me.get(primaryKey);
242 config = Ext.apply({}, storeConfig, {
243 model : associatedModel,
245 remoteFilter : false,
246 modelDefaults: modelDefaults
249 me[storeName] = Ext.create('Ext.data.Store', config);
251 me[storeName].load();
255 return me[storeName];
259 <span id='Ext-data.HasManyAssociation-method-read'> /**
260 </span> * Read associated data
262 * @param {Ext.data.Model} record The record we're writing to
263 * @param {Ext.data.reader.Reader} reader The reader for the associated model
264 * @param {Object} associationData The raw associated data
266 read: function(record, reader, associationData){
267 var store = record[this.name](),
270 store.add(reader.read(associationData).records);
272 //now that we've added the related records to the hasMany association, set the inverse belongsTo
273 //association on each of them if it exists
274 inverse = this.associatedModel.prototype.associations.findBy(function(assoc){
275 return assoc.type === 'belongsTo' && assoc.associatedName === record.$className;
278 //if the inverse association was found, set it now on each record we've just created
280 store.data.each(function(associatedRecord){
281 associatedRecord[inverse.instanceName] = record;
285 });</pre></pre></body></html>