Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExtJS waiting for multiple stores to load

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.

like image 999
Alex Ivasyuv Avatar asked Feb 21 '12 14:02

Alex Ivasyuv


5 Answers

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.

like image 85
McCroskey Avatar answered Nov 09 '22 12:11

McCroskey


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
    }
}
like image 29
egerardus Avatar answered Nov 09 '22 12:11

egerardus


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.

like image 31
Stephen Friedrich Avatar answered Nov 09 '22 11:11

Stephen Friedrich


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.

like image 23
nscrob Avatar answered Nov 09 '22 13:11

nscrob


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);
like image 32
sulhan Avatar answered Nov 09 '22 11:11

sulhan