John Hall
John Hall

Reputation: 1346

ExtJS Automatically populating a model property via an association

I am using ExtJS 4.1.0

Say I have a couple simple model's connected via a hasMany association. The models represent an order and order contents...

Ext.define('App.model.Order', 
{
    extend: 'Ext.data.Model',
    fields: ['id', 'order_date', 'order_total', 'contents' ],
    associations: [{
            type           : 'hasMany',
            model          : 'App.model.OrderContents',
            name           : 'getContents', /** magic method */
            primaryKey     : 'id',
            foreignKey     : 'order_id',
            autoLoad       : false
    }],

    /** Proxy Definition here.. */

});

Ext.define('App.model.OrderContents', 
{
    extend: 'Ext.data.Model',
    fields: ['id', 'order_id', 'item_id' ],

    /** Proxy Definition here.. */

});

Now, what if I want the contents property of my App.model.Order to be automatically set when an Order model is instantiated? For a temporary solution, I have added the following method to the Order model:

Ext.define('App.model.Order', 
{

/** Model definition ... */

    loadContents: function()
    {
       this.getContents().load({
            callback: function()
            {
                this.set('contents', arguments[0]);
            },
            scope: this
        });

    }
});

In order to have an Order object with contents readily available, I must do the following:

var myOrder = new App.model.Order({id:1, order_date:'12-15-2012', order_total:100});
myOrder.getData(true); // contents will be null
myOrder.loadContents();
myOrder.getData(); // contents will be an array of OrderContents

I have tried overloading the constructor for App.model.Order but no matter what, I cannot get access to the data loaded by the association even if I perform a callback on the async request for the association data.

Ultimately I would like to be able to retrieve an Order from my App.store.Orders and have the retrieved record already have its contents property set, but I just can't figure it out! If I retrieve a record from the store as follows:

myStore = Ext.getStore('OrderStore');
myOrder = myStore.findRecord('id',1);
myOrder.getData(); // contents will be null
myOrder.loadContents();
myOrder.getData(); // contents will be an array of OrderContents

I'm really just trying to cut down on having to .loadContents() for every instance of App.model.Order throughout my application; this seems like it should be very easy to accomplish. What am I missing?!

Thanks for your time!

Upvotes: 1

Views: 1911

Answers (3)

lontivero
lontivero

Reputation: 5275

This was not tested but It should work.

Ext.define('App.model.Order', 
{
    extend: 'Ext.data.Model',
    fields: ['id', 'order_date', 'order_total', 'contents' ],
    associations: [{
            type           : 'hasMany',
            model          : 'App.model.OrderContents',
            name           : 'getContents', /** magic method */
            primaryKey     : 'id',
            foreignKey     : 'order_id',
            autoLoad       : false
    }],
    load: function(id, config) {
            config = Ext.apply({
                  success: function(record, operation) {
                        store.getContents().load();
                  },
            }, config);
            this.callParent([id, config]);
    },
    /** Proxy Definition here.. */

});

Update: You could write your own load method (in the example this is called loadAll) as follow:

    Ext.define('App.model.OrderContents', 
    {
         extend: 'Ext.data.Model',
         fields: ['id', 'order_id', 'item_id' ],

         proxy: {
                type: 'memory',
                data: [
                    {id: 1, order_id: 1, item_id: 2}, 
                    {id: 2, order_id: 1, item_id: 3},
                    {id: 3, order_id: 21, item_id: 3}
                ],
              reader: 'json'            
         }

    });


    Ext.define('App.model.Order', 
         {
              extend: 'Ext.data.Model',
              fields: ['id', 'order_date', 'order_total', 'contents' ],
              associations: [{
                         type           : 'hasMany',
                         model          : 'App.model.OrderContents',
                         name           : 'getContents', /** magic method */
                         primaryKey     : 'id',
                         foreignKey     : 'order_id',
                         autoLoad       : false
              }],
              statics: {
                      loadAll: function(id, config) {
                         config = Ext.apply({
                                 callback: function(record, operation) {
                                     if(operation.wasSuccessful()){
                                        record.getContents().load();
                                        record.set('contents', record.getContents().getRange());
                                         }
                               },
                                scope: this
                         }, config);
                         App.model.Order.load(id, config);
                    }
              },
              proxy: {
                    type: 'memory',
                    data: {'id':1, 'order_date':null, 'order_total': 100, 'contents':[]},
                    reader: {
                        type: 'json'
                    }

              }
         });


var order;
App.model.Order.loadAll(1,{
    success: function(record){
        order = record;
    }
    });

console.log(order);

​You can see it working on jsfiddle:

http://jsfiddle.net/lontivero/X4gfR/

Upvotes: 1

John Hall
John Hall

Reputation: 1346

I managed a workaround by overloading the store's constructor:

Ext.define('App.store.Orders', {
    extend: 'Ext.data.Store',
    storeId: 'OrdersStore',
    model: 'App.model.Order',

    constructor: function()
    {
        this.superclass.constructor.call(this);
        this.on('load', function(store, records, success, eOpts){
            Ext.each(records, function(order){
               order.loadContents();
            });
        }, this);
    }
});

Hopefully this will help someone :)

Upvotes: 0

Zango
Zango

Reputation: 2387

You mentioned that you tried it with constuctor but I think you did something wrongly. If your constructor looks like this:

constructor: function(){
    var me = this;
    me.callParent([arguments]);
    me.loadContents();
}

I think you will get desired result...

Upvotes: 1

Related Questions