ExtJS waiting for multiple stores to load

10,877

Solution 1

We use this when there are several stores to wait on:

Ext.define('Ext.ux.StoreLoadCoordinator', {
mixins: {
    observable: 'Ext.util.Observable'
},
resetStoreLoadStates: function() {
    this.storeLoadStates = {};              

    Ext.each(this.stores, function(storeId) {
        this.storeLoadStates[storeId] = false;
    }, this);       
},    
isLoadingComplete: function() {
    for (var i=0; i<this.stores.length; i++) {
        var key = this.stores[i];

        if (this.storeLoadStates[key]==false) {
            return false;
        }
    }

    return true;        
},    
onStoreLoad: function(store, records, successful, eOpts, storeName) {
    this.storeLoadStates[store.storeId] = true;

    if (this.isLoadingComplete()==true) {
        this.fireEvent('load');
        this.resetStoreLoadStates();
    }
},    
constructor: function (config) {
    this.mixins.observable.constructor.call(this, config);

    this.resetStoreLoadStates();

    Ext.each(this.stores, function(storeId) {
        var store = Ext.StoreManager.lookup(storeId);

        store.on('load', Ext.bind(this.onStoreLoad, this, [storeId], true));
    }, this);

    this.addEvents(
        'load'            
    );
}});

To use it, pass in an array of the relevant storeIds:

var store1 =  Ext.create('Ext.data.Store', {
    storeId: 'Store1',
    .... (rest of store config)
}});        

var store2 =  Ext.create('Ext.data.Store', {
    storeId: 'Store2',
    .... (rest of store config)
}});        


var coordinatior = Ext.create('Ext.ux.StoreLoadCoordinator', {
    stores: ['Store1', 'Store2'],
    listeners: {
        load: function() {
           // Do post-load work
        }
    }
});         

This will give you a single load event to handle for multiple stores. Please note that this requires Ext 4.x or later.

Solution 2

I have had some projects that required several stores to be loaded before working with the data. I added a callback on them to check if each item in the Ext.data.StoreManager was loaded and if so it would do what I needed with the data.

To add stores to the StoreManager you just have to give it a storeId in its config, something like this:

var store1 = Ext.create('Ext.data.Store', {
    model: myModel,
    storeId: 'store1', //<-- adds this to Ext.data.StoreManager
    proxy: {
        type: 'ajax', 
        url: 'url...',
        reader: 'json'
    },
    autoLoad: {
        callback: initData
    }
});

var store2 = Ext.create('Ext.data.Store', {
    model: myModel,
    storeId: 'store2',
    proxy: {
        type: 'ajax', 
        url: 'url...',
        reader: 'json'
    },
    autoLoad: {
        callback: initData
    }
});

// Initialize store dependencies when all stores are loaded
function initData() {
    var loaded;
    Ext.data.StoreManager.each( function(store) {
        loaded = !store.isLoading();       
        return loaded;
    });
    if(loaded) {
        // do stuff with the data
    }
}

Solution 3

Usually I avoid the problem because I strive to minimize client/server roundtrips and improve performance: I set autoLoad to false on the store, then do an explicit ajax request that gets the data for all stores at once, then use store.loadData() to directly set it to each store. The downside is of course that it requires more code and results in tighter coupling.

Solution 4

i think you can add load listeners for both stores, and check if the other one finished ...

this.getStore('store1').on('load',function(store){
   if (this.getStore('store2').isLoading() == false ){
     // callMethod to perform action ....
   }
},this);

this.getStore('store2').on('load',function(store){
   if (this.getStore('store1').isLoading() == false ){
      // callMethod to perform action....
   }
},this);

I think this way it will call the method only when they are both loaded assuming that you know the request for load has been made for both.

Solution 5

I use chain loading stores to solve this.

Cons: slower than it should be.

chainStoreLoad :function (stores, lastCall, idx)
{
    if (idx === stores.length) {
        if ("function" === typeof lastCall) {
            lastCall.call ();
        }
        return;
    }
    stores[idx].load (function (r,o,s) {
        Jx.chainStoreLoad (stores, lastCall, idx + 1);
    });
}

Example:

Jx.chainStoreLoad (
    [
        this.storeAssetType
    ,   this.storeAssetProcurement
    ,   this.storeAssetStatus
    ,   this.storeAssetLocation
    ,   this.storeSystemUser
    ]
,   function ()
    {
        self.panel.doRefresh (perm);
    }
,   0);
Share:
10,877
Alex Ivasyuv
Author by

Alex Ivasyuv

Updated on June 22, 2022

Comments

  • Alex Ivasyuv
    Alex Ivasyuv almost 2 years

    How would I go about waiting for multiple stores to load? I have a case where I need to do some work only when two different stores are loaded, so using the store.on("load", fn) of one store is not good enough.

  • aletzo
    aletzo over 11 years
    Not sure, but I think the downvote was due to loaded = !store.isLoading(); which should be loaded &= !store.isLoading();. See this jsfiddle. There should be a comment in any case, to help us all :)
  • Black
    Black over 10 years
    Excellent! Thank you