4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-data-HasManyAssociation'>/**
19 </span> * @author Ed Spencer
20 * @class Ext.data.HasManyAssociation
21 * @extends Ext.data.Association
23 * <p>Represents a one-to-many relationship between two models. Usually created indirectly via a model definition:</p>
25 <pre><code>
26 Ext.define('Product', {
27 extend: 'Ext.data.Model',
29 {name: 'id', type: 'int'},
30 {name: 'user_id', type: 'int'},
31 {name: 'name', type: 'string'}
36 extend: 'Ext.data.Model',
38 {name: 'id', type: 'int'},
39 {name: 'name', type: 'string'}
41 // we can use the hasMany shortcut on the model to create a hasMany association
42 hasMany: {model: 'Product', name: 'products'}
44 </pre></code>
46 * <p>Above we created Product and User models, and linked them by saying that a User hasMany Products. This gives
47 * us a new function on every User instance, in this case the function is called 'products' because that is the name
48 * we specified in the association configuration above.</p>
50 * <p>This new function returns a specialized {@link Ext.data.Store Store} which is automatically filtered to load
51 * only Products for the given model instance:</p>
53 <pre><code>
54 //first, we load up a User with id of 1
55 var user = Ext.ModelManager.create({id: 1, name: 'Ed'}, 'User');
57 //the user.products function was created automatically by the association and returns a {@link Ext.data.Store Store}
58 //the created store is automatically scoped to the set of Products for the User with id of 1
59 var products = user.products();
61 //we still have all of the usual Store functions, for example it's easy to add a Product for this User
63 name: 'Another Product'
66 //saves the changes to the store - this automatically sets the new Product's user_id to 1 before saving
68 </code></pre>
70 * <p>The new Store is only instantiated the first time you call products() to conserve memory and processing time,
71 * though calling products() a second time returns the same store instance.</p>
73 * <p><u>Custom filtering</u></p>
75 * <p>The Store is automatically furnished with a filter - by default this filter tells the store to only return
76 * records where the associated model's foreign key matches the owner model's primary key. For example, if a User
77 * with ID = 100 hasMany Products, the filter loads only Products with user_id == 100.</p>
79 * <p>Sometimes we want to filter by another field - for example in the case of a Twitter search application we may
80 * have models for Search and Tweet:</p>
82 <pre><code>
83 Ext.define('Search', {
84 extend: 'Ext.data.Model',
92 filterProperty: 'query'
97 extend: 'Ext.data.Model',
99 'id', 'text', 'from_user'
103 //returns a Store filtered by the filterProperty
104 var store = new Search({query: 'Sencha Touch'}).tweets();
105 </code></pre>
107 * <p>The tweets association above is filtered by the query property by setting the {@link #filterProperty}, and is
108 * equivalent to this:</p>
110 <pre><code>
111 var store = new Ext.data.Store({
116 value : 'Sencha Touch'
120 </code></pre>
122 Ext.define('Ext.data.HasManyAssociation', {
123 extend: 'Ext.data.Association',
124 requires: ['Ext.util.Inflector'],
126 alias: 'association.hasmany',
128 <span id='Ext-data-HasManyAssociation-cfg-foreignKey'> /**
129 </span> * @cfg {String} foreignKey The name of the foreign key on the associated model that links it to the owner
130 * model. Defaults to the lowercased name of the owner model plus "_id", e.g. an association with a where a
131 * model called Group hasMany Users would create 'group_id' as the foreign key. When the remote store is loaded,
132 * the store is automatically filtered so that only records with a matching foreign key are included in the
133 * resulting child store. This can be overridden by specifying the {@link #filterProperty}.
134 * <pre><code>
135 Ext.define('Group', {
136 extend: 'Ext.data.Model',
137 fields: ['id', 'name'],
142 extend: 'Ext.data.Model',
143 fields: ['id', 'name', 'group_id'], // refers to the id of the group that this user belongs to
146 * </code></pre>
149 <span id='Ext-data-HasManyAssociation-cfg-name'> /**
150 </span> * @cfg {String} name The name of the function to create on the owner model to retrieve the child store.
151 * If not specified, the pluralized name of the child model is used.
152 * <pre><code>
153 // This will create a users() method on any Group model instance
154 Ext.define('Group', {
155 extend: 'Ext.data.Model',
156 fields: ['id', 'name'],
159 var group = new Group();
160 console.log(group.users());
162 // The method to retrieve the users will now be getUserList
163 Ext.define('Group', {
164 extend: 'Ext.data.Model',
165 fields: ['id', 'name'],
166 hasMany: {model: 'User', name: 'getUserList'}
168 var group = new Group();
169 console.log(group.getUserList());
170 * </code></pre>
173 <span id='Ext-data-HasManyAssociation-cfg-storeConfig'> /**
174 </span> * @cfg {Object} storeConfig Optional configuration object that will be passed to the generated Store. Defaults to
178 <span id='Ext-data-HasManyAssociation-cfg-filterProperty'> /**
179 </span> * @cfg {String} filterProperty Optionally overrides the default filter that is set up on the associated Store. If
180 * this is not set, a filter is automatically created which filters the association based on the configured
181 * {@link #foreignKey}. See intro docs for more details. Defaults to undefined
184 <span id='Ext-data-HasManyAssociation-cfg-autoLoad'> /**
185 </span> * @cfg {Boolean} autoLoad True to automatically load the related store from a remote source when instantiated.
186 * Defaults to <tt>false</tt>.
189 <span id='Ext-data-HasManyAssociation-cfg-type'> /**
190 </span> * @cfg {String} type The type configuration can be used when creating associations using a configuration object.
191 * Use 'hasMany' to create a HasManyAssocation
192 * <pre><code>
197 * </code></pre>
200 constructor: function(config) {
205 me.callParent(arguments);
207 me.name = me.name || Ext.util.Inflector.pluralize(me.associatedName.toLowerCase());
209 ownerProto = me.ownerModel.prototype;
213 storeName : name + "Store",
214 foreignKey: me.ownerName.toLowerCase() + "_id"
217 ownerProto[name] = me.createStore();
220 <span id='Ext-data-HasManyAssociation-method-createStore'> /**
222 * Creates a function that returns an Ext.data.Store which is configured to load a set of data filtered
223 * by the owner model's primary key - e.g. in a hasMany association where Group hasMany Users, this function
224 * returns a Store configured to return the filtered set of a single Group's Users.
225 * @return {Function} The store-generating function
227 createStore: function() {
229 associatedModel = that.associatedModel,
230 storeName = that.storeName,
231 foreignKey = that.foreignKey,
232 primaryKey = that.primaryKey,
233 filterProperty = that.filterProperty,
234 autoLoad = that.autoLoad,
235 storeConfig = that.storeConfig || {};
242 if (me[storeName] === undefined) {
243 if (filterProperty) {
245 property : filterProperty,
246 value : me.get(filterProperty),
251 property : foreignKey,
252 value : me.get(primaryKey),
257 modelDefaults[foreignKey] = me.get(primaryKey);
259 config = Ext.apply({}, storeConfig, {
260 model : associatedModel,
262 remoteFilter : false,
263 modelDefaults: modelDefaults
266 me[storeName] = Ext.create('Ext.data.Store', config);
268 me[storeName].load();
272 return me[storeName];
276 <span id='Ext-data-HasManyAssociation-method-read'> /**
277 </span> * Read associated data
279 * @param {Ext.data.Model} record The record we're writing to
280 * @param {Ext.data.reader.Reader} reader The reader for the associated model
281 * @param {Object} associationData The raw associated data
283 read: function(record, reader, associationData){
284 var store = record[this.name](),
287 store.add(reader.read(associationData).records);
289 //now that we've added the related records to the hasMany association, set the inverse belongsTo
290 //association on each of them if it exists
291 inverse = this.associatedModel.prototype.associations.findBy(function(assoc){
292 return assoc.type === 'belongsTo' && assoc.associatedName === record.$className;
295 //if the inverse association was found, set it now on each record we've just created
297 store.data.each(function(associatedRecord){
298 associatedRecord[inverse.instanceName] = record;