Results 1 to 4 of 4

Thread: AJAX Store & loading data from nested hasMany association

  1. #1
    Sencha User kitesurf's Avatar
    Join Date
    Jan 2012
    Location
    London, England
    Posts
    78
    Answers
    4
    Vote Rating
    7
      0  

    Default AJAX Store & loading data from nested hasMany association

    I have a store and model called 'availability'. On the availability model I have a hasMany association to balanceItems. This in turn also has a hasMany association to 'movements'.

    When I load the AJAX availability for the first time, I get all the data I expect, all good.

    However, if the back-end data changes and I do another availability store load(), the data in the hasMany associations is not updated.

    Actually, that's not strictly true, it depends how I access the data that is the cause for difference.

    In debug I wait for the callback to return from the AJAX call and I then inspect the store object after getting the store using the storemgr:

    Code:
    Ext.StoreMgr.get("AvailabilityStore")
    The hasMany association I am interested in is 'movements'. As far as I can make out, Sencha automatically creates a 'store' for this hasMany assocation called 'movementsStore'.

    If I look at the store data item in debug using the following path, I still have old data from when the store was first loaded:
    Code:
    availabilityStore.getAt(0).balanceItemsStore.data.all[0].data.movements[3]
    
    
    • balance: 139186
    • balanceitemsmodel_id: "1010-0100"
    • creditAmount: null
    • date: Thu Feb 02 2012 00:00:00 GMT+0000 (GMT)
    • debitAmount: 5250
    • description: "Invoice x 6"
    • formattedBalance: "139,186.00"
    • formattedCreditAmount: " "
    • formattedDate: "2 Feb 2012"
    • formattedDebitAmount: "5,250.00"
    • id: "ext-record-9"
    • xindex: 4
    • __proto__: Object
    If however I access it down the .raw route, I can see the updated data:
    Code:
    availabilityStore.getAt(0).raw.balanceItems[0].movements
    
    
    • balance: 139419
    • creditAmount: null
    • date: 1328140800000
    • debitAmount: 5483
    • description: "Invoice x 7"
    • __proto__: Object
    What I don't understand is why is the data not the same? Do I have to do some kind of sync on the automatically created hasMany stores that Sencha has created?

    I have included a copy of the full store object below as well as my model definitions. Hopefully someone can spot where I am going wrong or correct my interpretation of how to do this?

    Many thanks!

    • _data: Object
    • balanceItemsStore: Ext.apply.create.f
      • _data: Ext.apply.create.f
      • _filters: Array[1]
      • _model: function (){return this.constructor.apply(this,arguments)}
      • _modelDefaults: Ext.Object.classify.c
      • _proxy: Ext.apply.create.f
      • _remoteFilter: true
      • _remoteSort: false
      • _storeId: "ext-data-store-41"
      • _syncRemovedRecords: false
      • config: Ext.Object.classify.c
      • data: Ext.apply.create.f
        • _autoFilter: false
        • _autoSort: true
        • _filterRoot: "data"
        • _filters: Ext.apply.create.f
        • _sortRoot: "data"
        • all: Array[7]
          • 0: Ext.apply.create.f
            • _data: Object
            • data: Object
            • dirty: true
            • editing: false
            • id: "ext-record-10"
            • internalId: "1010-0100"
            • modified: Object
            • movementsStore: Ext.apply.create.f
              • _data: Ext.apply.create.f
              • _filters: Array[1]
              • _model: function (){return this.constructor.apply(this,arguments)}
              • _modelDefaults: Ext.Object.classify.c
              • _proxy: Ext.apply.create.f
              • _remoteFilter: true
              • _remoteSort: false
              • _storeId: "ext-data-store-2"
              • _syncRemovedRecords: false
              • config: Ext.Object.classify.c
              • data: Ext.apply.create.f
                • _autoFilter: false
                • _autoSort: true
                • _filterRoot: "data"
                • _filters: Ext.apply.create.f
                • _sortRoot: "data"
                • all: Array[4]
                  • 0: Ext.apply.create.f
                  • 1: Ext.apply.create.f
                  • 2: Ext.apply.create.f
                  • 3: Ext.apply.create.f
                    • _data: Object
                    • data: Object
                      • balance: 139186
                      • balanceitemsmodel_id: "1010-0100"
                      • creditAmount: null
                      • date: Thu Feb 02 2012 00:00:00 GMT+0000 (GMT)
                      • debitAmount: 5250
                      • description: "Invoice x 6"
                      • formattedBalance: "139,186.00"
                      • formattedCreditAmount: " "
                      • formattedDate: "2 Feb 2012"
                      • formattedDebitAmount: "5,250.00"
                      • id: "ext-record-9"
                      • xindex: 4
                      • __proto__: Object

                    • dirty: true
                    • editing: false
                    • id: "ext-record-9"
                    • internalId: "ext-record-9"
                    • modified: Object
                    • phantom: true
                    • raw: Object
                    • stores: Array[2]
                    • __proto__: a

                  • length: 4
                  • __proto__: Array[0]

                • config: Ext.Object.classify.c
                • dirtyFilterFn: true
                • dirtyIndices: false
                • filtered: true
                • getKey: function (a){return a.getId()}
                • indices: Object
                • initConfig: function (){}
                • initialConfig: Object
                • items: Array[4]
                • keys: Array[4]
                • length: 4
                • map: Object
                • __proto__: a

              • eventDispatcher: Ext.apply.create.f
              • getEventDispatcher: function (){return this.eventDispatcher}
              • getId: function (){return this.id}
              • getObservableId: function (){return this.observableId}
              • getUniqueId: function (){return this.id}
              • id: "ext-data-store-2"
              • initConfig: function (){}
              • initialConfig: Object
              • managedListeners: Object
              • observableId: "#ext-data-store-2"
              • removed: Array[0]
              • usedSelectors: Array[1]
              • __proto__: a

            • raw: Object
            • stores: Array[12]
            • __proto__: a

          • 1: Ext.apply.create.f
          • 2: Ext.apply.create.f
          • 3: Ext.apply.create.f
          • 4: Ext.apply.create.f
          • 5: Ext.apply.create.f
          • 6: Ext.apply.create.f
          • length: 7
          • __proto__: Array[0]

        • config: Ext.Object.classify.c
        • dirtyFilterFn: true
        • dirtyIndices: true
        • filtered: true
        • getKey: function (a){return a.getId()}
        • indices: Object
        • initConfig: function (){}
        • initialConfig: Object
        • items: Array[7]
        • keys: Array[7]
        • length: 7
        • map: Object
        • __proto__: a

      • eventDispatcher: Ext.apply.create.f
      • getEventDispatcher: function (){return this.eventDispatcher}
      • getId: function (){return this.id}
      • getObservableId: function (){return this.observableId}
      • getUniqueId: function (){return this.id}
      • id: "ext-data-store-41"
      • initConfig: function (){}
      • initialConfig: Object
      • managedListeners: Object
      • observableId: "#ext-data-store-41"
      • removed: Array[0]
      • usedSelectors: Array[1]
      • __proto__: a

    • data: Object
    • id: "ext-record-43"
    • internalId: "ext-record-43"
    • modified: Object
    • paymentMethodsStore: Ext.apply.create.f
    • paymentRecipientsStore: Ext.apply.create.f
    • phantom: true
    • raw: Object
      • asAtDate: 1350246360000
      • balanceItems: Array[8]
        • 0: Object
          • amount: 139419
          • hasMovements: true
          • id: "1010-0100"
          • label: "Sales Ledger"
          • maxPaymentRequest: false
          • movements: Array[4]
            • 0: Object
            • 1: Object
            • 2: Object
            • 3: Object
              • balance: 139419
              • creditAmount: null
              • date: 1328140800000
              • debitAmount: 5483
              • description: "Invoice x 7"
              • __proto__: Object

            • length: 4
            • __proto__: Array[0]

          • pendingPayments: false
          • __proto__: Object

        • 1: Object
        • 2: Object
        • 3: Object
        • 4: Object
        • 5: Object
        • 6: Object
        • 7: Object
        • length: 8
        • __proto__: Array[0]

      • paymentMethods: Array[1]
      • paymentRecipients: Array[1]
      • __proto__: Object

    • stores: Array[1]
    • __proto__: a

    Code:
    Ext.define('Aries.model.AvailabilityModel', {
        extend: 'Ext.data.Model',
    
        uses: [
            'Aries.model.BalanceItemsModel',
            'Aries.model.PaymentMethodModel',
            'Aries.model.PaymentRecipientModel'
        ],
    
        config: {
            fields: [
                {
                    name: 'asAtDate',
                    dateFormat: 'time',
                    type: 'date'
                }
            ],
            hasMany: [
                {
                    associationKey: 'balanceItems',
                    model: 'Aries.model.BalanceItemsModel',
                    name: 'balanceItems'
                },
                {
                    associationKey: 'paymentMethods',
                    model: 'Aries.model.PaymentMethodModel',
                    name: 'paymentMethods'
                },
                {
                    associationKey: 'paymentRecipients',
                    model: 'Aries.model.PaymentRecipientModel',
                    name: 'paymentRecipients'
                }
            ]
        }
    });
    Code:
    Ext.define('Aries.model.BalanceItemsModel', {
        extend: 'Ext.data.Model',
        alias: 'model.BalanceItemsModel',
    
        uses: [
            'Aries.model.NewMovementModel'
        ],
    
        config: {
            fields: [
                {
                    name: 'id',
                    type: 'string'
                },
                {
                    name: 'label',
                    type: 'string'
                },
                {
                    name: 'amount',
                    type: 'float'
                },
                {
                    name: 'pendingPayments',
                    type: 'boolean'
                },
                {
                    name: 'maxPaymentRequest',
                    type: 'boolean'
                },
                {
                    name: 'hasMovements',
                    type: 'boolean'
                }
            ],
            hasMany: {
                associationKey: 'movements',
                model: 'Aries.model.NewMovementModel',
                name: 'movements'
            }
        }
    });
    Code:
    Ext.define('Aries.model.NewMovementModel', {
        extend: 'Ext.data.Model',
    
        config: {
            fields: [
                {
                    name: 'date',
                    dateFormat: 'time',
                    type: 'date'
                },
                {
                    name: 'formattedDate'
                },
                {
                    name: 'description'
                },
                {
                    name: 'creditAmount',
                    type: 'float'
                },
                {
                    name: 'formattedCreditAmount'
                },
                {
                    name: 'debitAmount',
                    type: 'float'
                },
                {
                    name: 'formattedDebitAmount'
                },
                {
                    name: 'balance',
                    type: 'float'
                },
                {
                    name: 'formattedBalance'
                }
            ]
        }
    });

  2. #2
    Sencha - Sr Software Engineer mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    39,556
    Answers
    3932
    Vote Rating
    1272
      0  

    Default

    It updates for me using 2.1.0 RC2

    Code:
    Ext.define('Product', {
        extend : 'Ext.data.Model',
        config : {
            fields : [
                {name : 'id', type : 'int'},
                {name : 'user_id', type : 'int'},
                {name : 'name', type : 'string'}
            ]
        }
    });
    
    Ext.define('User', {
        extend : 'Ext.data.Model',
        config : {
            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'}
        }
    });
    
    Ext.application({
        name   : 'Test',
    
        launch : function () {
    
            new Ext.data.Store({
                autoLoad  : true,
                model     : 'User',
                proxy     : {
                    type : 'ajax',
                    url  : 'data/json.json'
                },
                listeners : {
                    single : true,
                    load   : function(store, recs) {
                        var rec      = recs[0],
                            products = rec.products();
            
                        console.log(products.getAt(0).get('name'));
            
                        setTimeout(function() {
                            store.load(function(recs) {
                                var rec      = recs[0],
                                    products = rec.products();
            
                                console.log(products.getAt(0).get('name'));
                            });
                        }, 5000);
                    }
                }
            });
    
        }
    });
    This json at first:

    Code:
    [
        {
            "id"       : 1,
            "name"     : "Mitchell Simoens",
            "products" : [
                {
                    "id"      : 2,
                    "user_id" : 1,
                    "name"    : "Apple"
                }
            ]
        }
    ]
    And I just changed Apple to Apples within 5 seconds and it consoles out Apple then Apples
    Mitchell Simoens @LikelyMitch
    Sencha Inc, Senior Software Engineer
    ________________
    Learn BBCode and use it! Checkout the CODE tag!

    Check out my GitHub, lots of nice things for Ext JS and Sencha Touch
    https://github.com/mitchellsimoens

  3. #3
    Sencha User kitesurf's Avatar
    Join Date
    Jan 2012
    Location
    London, England
    Posts
    78
    Answers
    4
    Vote Rating
    7
      0  

    Default

    Hi Mitchell,

    Thank you for taking the time to check this out!

    I am using version 2.0.1.1, so this may well have been fixed in 2.1.0.

    I've attached an updated version of the test which includes a further hasMany on products called sizes.

    I've also registered a 'users' store and use this to get my data after getting the store from the store mgr. Perhaps I am not doing this correctly or missing something conceptually. Would you mind doing some sanity checking on my code and testing this in 2.1.0 to see what you get. I've put in a debugger statement so as to have time to change a few of the values in the json file.

    In my tests it doesn't show any changes in the json file. It always remains the same as the initial data load.

    thanks!

    Code:
    Ext.define('Sizes', {
        extend : 'Ext.data.Model',
        config : {
            fields : [
                {name : 'id', type : 'string'},
                {name : 'desc', type : 'string'}
            ]
        }
    });
    
    Ext.define('Product', {
        extend : 'Ext.data.Model',
        config : {
            fields : [
                {name : 'id', type : 'int'},
                {name : 'user_id', type : 'int'},
                {name : 'name', type : 'string'}
            ],
            hasMany : {model : 'Sizes', name : 'sizes'}
        }
    });
    
    Ext.define('User', {
        extend : 'Ext.data.Model',
        config : {
            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'}
        }
    });
    
    Ext.application({
        name   : 'Test',
    
        launch : function () {
    
            new Ext.data.Store({
                autoLoad  : true,
                model     : 'User',
                storeId   : 'Users',
                proxy     : {
                    type : 'ajax',
                    url  : 'data/json.json'
                },
                listeners : {
                    single : true,
                    load   : function(store, recs) {
                                var userStores = Ext.StoreMgr.get("Users");
                                var user = Ext.StoreMgr.get("Users").getAt(0);
                                var product = user.products().getAt(0);
                                var sizes = product.sizes().getAt(0);                            
                                console.log(user.get('name'));
                                console.log(product.get('name'));
                                console.log(sizes.get('desc'));
            
                        setTimeout(function() {
                            store.load(function(recs) {
                                debugger;
                                var userStores = Ext.StoreMgr.get("Users");
                                var user = Ext.StoreMgr.get("Users").getAt(0);
                                var product = user.products().getAt(0);
                                var sizes = product.sizes().getAt(0);                            
                                console.log(user.get('name'));
                                console.log(product.get('name'));
                                console.log(sizes.get('desc'));
                            });
                        }, 5000);
                    }
                }
            });
    
        }
    });
    Code:
    [
        {
            "id"       : 1,
            "name"     : "Mitchell Simoens",
            "products" : [
                {
                    "id"      : 2,
                    "user_id" : 1,
                    "name"    : "Apple",
                    "sizes"   : [
                        {
                            "id"    : "S",
                            "desc"    : "Small"
                        },
                        {
                            "id"    : "M",
                            "desc"    : "Medium"
                        }
                        
                    ] 
                }
            ]
        }
    ]

  4. #4
    Sencha User
    Join Date
    Apr 2012
    Posts
    6
    Vote Rating
    2
      0  

    Default

    Hi,

    It seems this error still exists. I ran into the same problem.

    It only occurs when the hasMany store has less items than in the first call. If your related store has 3 items after the first load and 2 items after the second load the first two gets overwritten and number 3 will not be removed.

    I did not debug that much but I think the error is in

    Ext.data.Store - insert: function(index, records)

    or

    Ext.util.Collection - insertAll: function(index, insertItems)


    As a temporary fix you can delete the related store calling the removeAll method.

    Regards

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •