| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-data-association-HasMany'>/**</span> * @author Ed Spencer * @class Ext.data.association.HasMany *  * <p>Represents a one-to-many relationship between two models. Usually created indirectly via a model definition:</p> * <pre><code>Ext.define('Product', {    extend: 'Ext.data.Model',    fields: [        {name: 'id',      type: 'int'},        {name: 'user_id', type: 'int'},        {name: 'name',    type: 'string'}    ]});Ext.define('User', {    extend: 'Ext.data.Model',    fields: [        {name: 'id',   type: 'int'},        {name: 'name', type: 'string'}    ],    // we can use the hasMany shortcut on the model to create a hasMany association    hasMany: {model: 'Product', name: 'products'}});</pre></code>*  * <p>Above we created Product and User models, and linked them by saying that a User hasMany Products. This gives * us a new function on every User instance, in this case the function is called 'products' because that is the name * we specified in the association configuration above.</p> *  * <p>This new function returns a specialized {@link Ext.data.Store Store} which is automatically filtered to load * only Products for the given model instance:</p> * <pre><code>//first, we load up a User with id of 1var user = Ext.create('User', {id: 1, name: 'Ed'});//the user.products function was created automatically by the association and returns a {@link Ext.data.Store Store}//the created store is automatically scoped to the set of Products for the User with id of 1var products = user.products();//we still have all of the usual Store functions, for example it's easy to add a Product for this Userproducts.add({    name: 'Another Product'});//saves the changes to the store - this automatically sets the new Product's user_id to 1 before savingproducts.sync();</code></pre> *  * <p>The new Store is only instantiated the first time you call products() to conserve memory and processing time, * though calling products() a second time returns the same store instance.</p> *  * <p><u>Custom filtering</u></p> *  * <p>The Store is automatically furnished with a filter - by default this filter tells the store to only return * records where the associated model's foreign key matches the owner model's primary key. For example, if a User * with ID = 100 hasMany Products, the filter loads only Products with user_id == 100.</p> *  * <p>Sometimes we want to filter by another field - for example in the case of a Twitter search application we may * have models for Search and Tweet:</p> * <pre><code>Ext.define('Search', {    extend: 'Ext.data.Model',    fields: [        'id', 'query'    ],    hasMany: {        model: 'Tweet',        name : 'tweets',        filterProperty: 'query'    }});Ext.define('Tweet', {    extend: 'Ext.data.Model',    fields: [        'id', 'text', 'from_user'    ]});//returns a Store filtered by the filterPropertyvar store = new Search({query: 'Sencha Touch'}).tweets();</code></pre> *  * <p>The tweets association above is filtered by the query property by setting the {@link #filterProperty}, and is * equivalent to this:</p> * <pre><code>var store = Ext.create('Ext.data.Store', {    model: 'Tweet',    filters: [        {            property: 'query',            value   : 'Sencha Touch'        }    ]});</code></pre> */Ext.define('Ext.data.association.HasMany', {    extend: 'Ext.data.association.Association',    alternateClassName: 'Ext.data.HasManyAssociation',    requires: ['Ext.util.Inflector'],    alias: 'association.hasmany',<span id='Ext-data-association-HasMany-cfg-foreignKey'>    /**</span>     * @cfg {String} foreignKey The name of the foreign key on the associated model that links it to the owner     * model. Defaults to the lowercased name of the owner model plus "_id", e.g. an association with a where a     * model called Group hasMany Users would create 'group_id' as the foreign key. When the remote store is loaded,     * the store is automatically filtered so that only records with a matching foreign key are included in the      * resulting child store. This can be overridden by specifying the {@link #filterProperty}.     * <pre><code>Ext.define('Group', {    extend: 'Ext.data.Model',    fields: ['id', 'name'],    hasMany: 'User'});Ext.define('User', {    extend: 'Ext.data.Model',    fields: ['id', 'name', 'group_id'], // refers to the id of the group that this user belongs to    belongsTo: 'Group'});     * </code></pre>     */    <span id='Ext-data-association-HasMany-cfg-name'>    /**</span>     * @cfg {String} name The name of the function to create on the owner model to retrieve the child store.     * If not specified, the pluralized name of the child model is used.     * <pre><code>// This will create a users() method on any Group model instanceExt.define('Group', {    extend: 'Ext.data.Model',    fields: ['id', 'name'],    hasMany: 'User'});var group = new Group();console.log(group.users());// The method to retrieve the users will now be getUserListExt.define('Group', {    extend: 'Ext.data.Model',    fields: ['id', 'name'],    hasMany: {model: 'User', name: 'getUserList'}});var group = new Group();console.log(group.getUserList());     * </code></pre>     */    <span id='Ext-data-association-HasMany-cfg-storeConfig'>    /**</span>     * @cfg {Object} storeConfig Optional configuration object that will be passed to the generated Store. Defaults to      * undefined.     */    <span id='Ext-data-association-HasMany-cfg-filterProperty'>    /**</span>     * @cfg {String} filterProperty Optionally overrides the default filter that is set up on the associated Store. If     * this is not set, a filter is automatically created which filters the association based on the configured      * {@link #foreignKey}. See intro docs for more details. Defaults to undefined     */    <span id='Ext-data-association-HasMany-cfg-autoLoad'>    /**</span>     * @cfg {Boolean} autoLoad True to automatically load the related store from a remote source when instantiated.     * Defaults to <tt>false</tt>.     */    <span id='Ext-data-association-HasMany-cfg-type'>    /**</span>     * @cfg {String} type The type configuration can be used when creating associations using a configuration object.     * Use 'hasMany' to create a HasMany association     * <pre><code>associations: [{    type: 'hasMany',    model: 'User'}]     * </code></pre>     */        constructor: function(config) {        var me = this,            ownerProto,            name;                    me.callParent(arguments);                me.name = me.name || Ext.util.Inflector.pluralize(me.associatedName.toLowerCase());                ownerProto = me.ownerModel.prototype;        name = me.name;                Ext.applyIf(me, {            storeName : name + "Store",            foreignKey: me.ownerName.toLowerCase() + "_id"        });                ownerProto[name] = me.createStore();    },    <span id='Ext-data-association-HasMany-method-createStore'>    /**</span>     * @private     * Creates a function that returns an Ext.data.Store which is configured to load a set of data filtered     * by the owner model's primary key - e.g. in a hasMany association where Group hasMany Users, this function     * returns a Store configured to return the filtered set of a single Group's Users.     * @return {Function} The store-generating function     */    createStore: function() {        var that            = this,            associatedModel = that.associatedModel,            storeName       = that.storeName,            foreignKey      = that.foreignKey,            primaryKey      = that.primaryKey,            filterProperty  = that.filterProperty,            autoLoad        = that.autoLoad,            storeConfig     = that.storeConfig || {};                return function() {            var me = this,                config, filter,                modelDefaults = {};                            if (me[storeName] === undefined) {                if (filterProperty) {                    filter = {                        property  : filterProperty,                        value     : me.get(filterProperty),                        exactMatch: true                    };                } else {                    filter = {                        property  : foreignKey,                        value     : me.get(primaryKey),                        exactMatch: true                    };                }                                modelDefaults[foreignKey] = me.get(primaryKey);                                config = Ext.apply({}, storeConfig, {                    model        : associatedModel,                    filters      : [filter],                    remoteFilter : false,                    modelDefaults: modelDefaults                });                                me[storeName] = Ext.data.AbstractStore.create(config);                if (autoLoad) {                    me[storeName].load();                }            }                        return me[storeName];        };    },    <span id='Ext-data-association-HasMany-method-read'>    /**</span>     * Read associated data     * @private     * @param {Ext.data.Model} record The record we're writing to     * @param {Ext.data.reader.Reader} reader The reader for the associated model     * @param {Object} associationData The raw associated data     */    read: function(record, reader, associationData){        var store = record[this.name](),            inverse,            items, iLen, i;            store.add(reader.read(associationData).records);            //now that we've added the related records to the hasMany association, set the inverse belongsTo        //association on each of them if it exists        inverse = this.associatedModel.prototype.associations.findBy(function(assoc){            return assoc.type === 'belongsTo' && assoc.associatedName === record.$className;        });            //if the inverse association was found, set it now on each record we've just created        if (inverse) {            items = store.data.items;            iLen  = items.length;            for (i = 0; i < iLen; i++) {                items[i][inverse.instanceName] = record;            }        }    }});</pre></body></html>
 |