32

I have a set of combo boxes that are driven by five stores and I want to fire a function once all the stores are completely loaded. What is the recommended way of doing this? I could do something like this but it feels kludgy:

var store1Loaded = false;
var store2Loaded = false;

store1.on('load', function(){
    store1Loaded = true;
});

store2.on('load', function(){
    store1Loaded = true;
});


store1.load();
store2.load();

function WaitForFunction()
{
    if (!store1Loaded || !store2Loaded)) {
       setTimeout( WaitForFunction, 100);
       return;
    }
    AllStoresLoaded();
}

function AllStoresLoaded(){
      //Do Something
}
Greg Finzer
  • 6,714
  • 21
  • 80
  • 125

7 Answers7

26

Use the store.isLoading() method, I think that is what it is for. I use it and it works fine.

  1. Configure the stores that you want to be loaded before performing some logic with a storeId config.

  2. Put these storeIds into an array.

  3. Whenever one of these stores is loaded iterate through the array, lookup the store with Ext.getStore and call isLoading on it.

  4. If none of the stores in the array are still loading, perform your logic.

For example, say I want store1 and store2 loaded before I perform some logic (I am showing this in non-MVC pattern because it looks like you are not using MVC pattern from your snippet).

var store1 = Ext.create('Ext.data.Store', {
    model: myModel,
    storeId: 'store1', // store needs to be done MVC style or have this config
    proxy: {
        type: 'ajax', 
        url: 'url...',
        reader: 'json'
    },
    autoLoad: {
        callback: initData // do this function when it loads
    }
});

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

// the stores to be checked
var myComboStores = ['store1', 'store2']

// function does logic if they are both finished loading
function initData() {
    var loaded = true;
    Ext.each(myComboStores, function(storeId) {
        var store = Ext.getStore(storeId);
        if (store.isLoading()) {
            loaded = false;
        }
    });
    if(loaded) {
        // do stuff with the data
    }
}
Andron
  • 6,413
  • 4
  • 43
  • 56
egerardus
  • 11,316
  • 12
  • 80
  • 123
  • Does `isLoading()` equal `false` when store is not loaded? Could it be a problem? – o_nix Jun 13 '12 at 01:00
  • @o_nix by "not loaded" do you mean "has no records"? In my experience `isLoading` only equals true in the time between a request and response from the server. So if a server returns no records then it would still be true. This has never been a problem for me. The main point of it for me is simply to know when the request comes back. Different logic could be implemented if you want to handle a response with no results. – egerardus Jun 13 '12 at 01:57
  • 1
    In order to keep checking maybe setTimeout(me.initData,500) should work. – VAAA Jul 10 '14 at 01:52
  • @VAAA The point of this is not to have to keep checking with a timer, `initData` is called whenever one of the stores finish loading because it is in the `load` config. When it is called it checks if all the other stores are finished loading, if true it performs whatever logic is needed – egerardus May 19 '15 at 22:46
8

Using timeouts isn't a great solution, however also having to rely on everything in the store manager isn't great either.

I'd do something like:

var allStores = [store1, store2],
    len = allStores.length,
    loadedStores = 0,
    i = 0;

for (; i < len; ++i) {
    allStores[i].on('load', check, null, {single: true});
}

function check() {
    if (++loadedStores === len) {
        AllStoresLoaded();
    }
}

function AllStoresLoaded() {
    //Do Something
}

If you're using it alot you could even turn it into a class.

Evan Trimboli
  • 29,900
  • 6
  • 45
  • 66
2

Extend the store - add the 'loaded' property to the child class, override 'initComponent()' and attach to 'load' event inside it, raise the 'loaded' to true inside the event handler, add the 'isLoaded()' method returning value of the 'loaded' property.

Other way, if you use http transport - store.proxy.conn.isLoading()

Take a look at this

pacman
  • 1,061
  • 1
  • 17
  • 36
2
function storeLoadingHandler(justLoadedStore) {
    // I use some quick hacky flag, you can do it by your own way
    justLoadedStore.loaded = true;

    var allStoresLoaded = true;

    // just walk through all stores registered in the application
    // do not forget to use MVC-style stores or add 'storeId' manually
    // or register every store with your custom code
    Ext.StoreManager.each(function(existingStore) {
        // we have to ignore system stores
        if (existingStore.storeId != 'ext-empty-store') {
            if (!existingStore.loaded) { // our flag or undefined
                // nope, at least one of stores is not loaded
                allStoresLoaded = false;

                return false
            }
        }
    })

    if (allStoresLoaded) // then do something
        alert('All stores are loaded.');
}

// add the loading handler for all stores
Ext.StoreManager.each(function() {
    this.on('load', storeLoadingHandler);
})
o_nix
  • 1,146
  • 1
  • 16
  • 30
2

If you have a problem because the combobox are not displayed/refreshed properly when the stores take too long to load, the solution is to create every store which is to be used in a combobox like this

Ext.create("Ext.data.Store", {
    ...,
    loading: true,
    ...
});

Comboboxes check that parameter in the stores they use to refresh the info once it's loaded, but sometimes the combobox is created and refreshed even before the store starts to load and the 'loading' flag is set to true, and then it won't refresh its value when the store finishes loading. Setting it to true explicitly fixes the issue. I don't know if that is your case, but I thought I would mention it in case it is.

Triqui
  • 69
  • 3
  • We had the exact problem because our ViewModel was returned as `async Task` (Asp.Net MVC) and comboboxes were trying to set their values before their stores were loaded. Setting `loading:true` absolutely fixed the issue. – mdisibio Jan 22 '16 at 23:52
  • This saved me a ton of time/code. We have the same combobox store "race" condition where form binding is happening before the combobox has loaded its store. I found this thread thinking I was going to have to write customer code to wait for all stores to load before continuing with my form.loadRecord operations. This simple store config fixed the problem right up. Many thanks! – Wade Bee Jul 27 '17 at 21:42
1

Use Deft JS

Deft JS is a addon injected via dependancy injection. It allows user to add promises in AJAX calls and the promise is resolved only when the call is done. Link for Deft JS. Use Ext.defer.All(); to load all your 5 stores and a particular callback function will be called once all the stores are loaded. In that function, Implement your logic.

1

ExtJs Store have method load and load method have callback function.

I have created a demo. you can check here Sencha fiddle

This function will create store and return.

function createStore(id) {
    return Ext.create('Ext.data.Store', {
        storeId: 'store_' + id,
        alias: 'store.store_' + id,
        proxy: {
            type: 'ajax',
            url: 'data.json',
            timeout: 300000,
            reader: {
                type: 'json',
                rootProperty: 'data'
            }
        }
    });
}

For Example I have array of store. It contain storeId or alias.

var storeArry = [],
    store = '';

for (var key = 0; key < 5; key++) {
    storeArry.push(createStore(key).storeId);
}

On every store callback we can remove data from storeArray or maintain a variable for checking.

Ext.getBody().mask('Please wait..');
Ext.defer(function () {
    Ext.getBody().unmask();
    Ext.Array.forEach(storeArry, function (storeId) {
        //For checking store is created or not
        //if store is not created we can create dyanamically using passing storeId/alias
        store = Ext.getStore(storeId);
        if (Ext.isDefined(store) == false) {
            store = Ext.create(storeId);
        }
        store.load({
            callback: function () {
                //On every store call back we can remove data from storeArray or maintain a veribale for checking.
                Ext.Array.remove(storeArry, this.storeId);
                if (storeArry.length == 0) {
                    Ext.Msg.alert('Success', 'All stored is loaded..!');
                }
            }
        });
    });
}, 3000);
Narendra Jadhav
  • 10,052
  • 15
  • 33
  • 44