11

In Sencha Touch, I often need to have an Ext.DataView panel that contains a small sub-set records or even a single record from the collection in the store.

For example I might have a Model for Car which has thousands of car records in it's app.stores.cars store but I want to show a smaller subset of these items (say; just sports cars) in my listOfSportsCars DataView while also showing the larger complete set of cars in my listOfCars DataView.

My first thought was to use multiple stores. So I'd have one main store for the big list of all cars, and a second store with a filter for my subset of sportscars. However, now updating a model from one store does not automatically update the record in the other store, so this defeats the purpose of using a DataView as the changes are not updated everywhere in the page when updating records.

My second attempt was to overwrite the collectData method on the DataView, which sounded exactly like what I was after:

var card = new Ext.DataView({
    store: app.stores.cars,
    collectData: function(records, startIndex){
        // map over the records and collect just the ones we want
        var r = [];
        for( var i=0; i<records.length; i++ )
            if( records[i].data.is_sports_car )
                r.push( this.prepareData(records[i].data, 0, records[i]) );
            return r;
    },
    tpl: new Ext.XTemplate([
            '<tpl for=".">',
                  '<div class="car">{name}</div>',
            '</tpl>'
    ]),
    itemSelector: 'div.car'
});

A full example can be found here.

But, although it's documented that I can/should override this method, Sencha Touch really doesn't like it when you mess around with the length of the array returned by collectData so this was a dead-end.

How do others deal with displaying/updating multiple collections of the same records?

UPDATE There was a bug preventing collectData from working as expected. The bug has since been fixed in Sencha Touch 1.1.0.

sra
  • 23,820
  • 7
  • 55
  • 89
Chris Farmiloe
  • 13,935
  • 5
  • 48
  • 57
  • 1
    Good question. I'm also using multiple stores and would like to know if there is a better approach. – Nicodemuz Mar 27 '11 at 14:17
  • Where exactly did you get the error? Have you tried to debug this? – sra May 03 '11 at 08:19
  • @sa When `replaceElement` is run when a record changes, ST appears to blindly try to find and replace the HTML for the record in ALL DataViews and does not attempt to fully refresh the DataView. It raises a `parentNode not found` error as a result of trying to update a record that can not be found in the filtered/collected list. I've added a link to a full gist example if anyone wants to try it out. – Chris Farmiloe May 03 '11 at 11:19
  • I've used your democode with the last ST release and opened all with chrome. But there is no error. If I hit the button the view got updated with skoda. Can you provide more information about the error, please? Like Test environment, versions and so on... – sra May 05 '11 at 09:07
  • @sra I'm dense. Add an answer telling me to update to the latest ST (where my bug is now fixed) and claim your bounty. I hadn't noticed I was running on the previous release. – Chris Farmiloe May 05 '11 at 18:25
  • @Chris I am glad that I was able to help you! The answer is added. – sra May 05 '11 at 18:53

4 Answers4

3

As written in the comment:

I've used your democode with the last Sencha Touch release and opened all with Google Chrome. In the current version the error is fixed. (Version 1.1)

sra
  • 23,820
  • 7
  • 55
  • 89
  • collectData() has been [removed](http://docs.sencha.com/touch/2.3.1/#!/api/Ext.dataview.DataView-method-collectData) since Sencha Touch 2.0. – Efran Cobisi Dec 20 '13 at 13:25
2

you could use Filters in order to get a subset of the data asociated to that store.

yourstore.filter('name', 'Joseph');

Also you should define 'root' as a function so it will always return an array. Readers in sencha touch asume you're always going to get an array as response, but it's not true if you are having a JSON with a single entry, try something like this:

root: function(data) {
                    if (data) {
                        if (data instanceof Array) {
                            return data;
                        } else {
                            return [data];
                        }                    
                    }  

The full code for the store could be like this:

YourApp.ViewName = new Ext.data.Store({
    model: 'YourApp.models.something',
    proxy: {
        type: 'scripttag',
        url: 'http://somerandomurl/service/json',
        extraParams: {
            param1: 'hello'                 
        },
        reader: {
            type: 'json',
            root: function(data) {
                    if (data) {
                        if (data instanceof Array) {
                            return data;
                        } else {
                            return [data];
                        }                    
                    }                
                }
        }
    },

});

Hope it helps.

1

I use the "filter" features in the Store. Not modifying the DataView (I use a List).

Here's a snippet where I will fiter out Programs with a catagory that fit's a regex. (I have Programs with a catagory field)

MyApp.stores.Programs.filter(function(object) {
    var regex = new RegExp(filterValue, 'i');
    return object.data.category.search(regex) >= 0; // found match
  });

You can clear the filter like this:

MyApp.stores.Programs.clearFilter(false);

This will update the DataView (I use a List) immediately (it's amazing).

So within your filter you could just filter out sports cars, or cars of a certain price, or whatever.

Hope that helps...

ballmw
  • 945
  • 7
  • 13
  • As I understand it though; adding a `filter` to a store will affect *all* DataViews/Lists that are bound to that store. So if I had two Lists on the page sitting next to each other, both bound to the same store, setting the filter would mean that *both* lists would become filtered. But the aim is to be able to have the two Lists display a different set of the same data – from the same store. – Chris Farmiloe Mar 28 '11 at 13:48
  • Yes, you're right, you may want to make sure your question is clear that that is the answer you're looking for. I'll keep an eye out for a solution... – ballmw Mar 28 '11 at 13:59
0

For my understanding of Sencha Touch this is not the best approach. If it can be still good for performance you shoud use a second "slave" store, with inline data (http://docs.sencha.com/touch/1-1/#!/api/Ext.data.Store) that you can populate automatically from main store with subset of information you want to show when an event occours on the master store, i.e. load event.

If you want to deal with just one store a solution I can imagine is to use an xtemplate with "tpl if" tag in the dataview where you want to show just some information http://docs.sencha.com/touch/1-1/#!/api/Ext. to write empty records. Maybe, also better solution, could be to use a custom filter function inside xtemplate, in order to put a css with visibility hidden on the items you don't want to see.

bovello
  • 131
  • 1
  • 4