Filtering Data Stores for Lists in Sencha Touch 2

April 20th, 2012

Sencha Touch 2 is a great way to develop both web mobile apps and natively wrapped apps, and has some excellent features for managing data stores. However there are instances in which continuously filtering and sorting a data store can become problematic. We are going to look at a situation where you might have one large datastore and places where different displays of that information is required.

Let's say you are designing a mobile application containing multiple pages (cards) and utilizing a tabpanel/carousel layout. Your data store is loaded up with a large number of records, and you have search functionality that displays matched records in a list. Although it would make sense to simply filter the store using RegExp there are a few reasons that make this less that ideal.

Whenever a store is filtered both sorters and groupers are reapplied, slowing the process and hindering performance. This happens as well when filters are cleared. Not only could you encounter delays in animation when moving in/out of the list (filtering on show, clearing filters on hide), but you won't be able to easily implement back button navigation without having to refilter the store. Combine this idea with a very large data store, multiple sublists, and a complex navigation design - you are probably starting to see the issue.

The best way to handle this, without setting up and managing duplicate stores in advance, would be to never filter your original store directly when dealing with lists. Instead you can create a separate method for searching the store and loading the list data directly. For example, let's say we have a store called cityStore containing cities (the model having a city and state code) and want to grab all cities that start with the letter S in the state of California. This data would then be displayed in a list called cityList. First, let's get the subset of data by using the queryBy method of the store:

var reg = new RegExp('^S', 'i');							
var results = cityStore.queryBy(function(record){
    var city = record.get('CityName'),
        state = record.get('StateCode');
    if(reg.test(city) && state == 'CA') {
        return true;
    }	
});

As you can see above, we now have a results object containing the records that matched the criteria we specified. Now time to load it into the list:

cityList.setStore({
    data: Ext.Array.pluck(results.getRange(),'data'),
    sorters: [{
    	property: 'CityName'
    }]	
});

By setting the store using the data you retrieved early you are essentially setting up a new store for the list to use. As this is technically a new store, you may have noticed you need to apply things such as sorters if they are needed. The automatically generated record IDs are the same as the original store, so when it comes to handling list selection you would do something like this to save the record ID and call it from the original store:

cityList.on('itemtap',function(list,index,element,record) {
    var id = record.getId();
    var originalRecord = cityStore.getById(id);
});	

When it's time to move you can forget about the list, and overwrite it with new data by repeating the above process. This ensures your original store is always kept unchanged, does not spend resources repeatedly filtering a large store, and let's you go back to the last sublist without reloading the data. This tactic proves even more useful if you are dealing with multiple sublists all using data from the same store.

Building Awesome Web Apps
HTML5 WebGL Android Apple iOS Windows Phone Leap Motion PhoneGap Google Glass