Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Request: Filter on a DataView

  1. #1
    Sencha User
    Join Date
    Sep 2011
    Posts
    46
    Answers
    1

    Post Answered: Request: Filter on a DataView

    I have a store for Categories. One category could have multiple subcategories, which can have subcategories as well. My idea was to create one categories store and three Dataviews:
    • The first DataView would filter on ParentID = 0 (root categories)
    • The second DataView would filter on ParentID = [id of root level]
    • The third DataView would filter on ParentID = [id of level 1]
    With quite a lot of sweat and tears I've managed to bend the DataView class to my needs and introduce a filter property that filters the store before translating the records into DataView list items. (it seems that the DataView class is very index oriented, which makes it tough to customize)

    Could you add this filter functionality to the DataView in one of the upcoming releases?

    The alternative would be to have three stores, but that is awful in terms of data retrieval and manageability.
    Is there perhaps an alternative that I've overlooked?

  2. I'm just suggesting the best way to do it right now. We have no plans to support this as it isn't a popular requested feature. I've added it to our internal tracking system however and we will review for 2.x.

  3. #2
    Sencha User rdougan's Avatar
    Join Date
    Oct 2008
    Posts
    1,159
    Answers
    93

    Default

    There is no way to do this in ST2, and we have no plans to support it either.

    Personally, I would setup 1 base store which handles your ajax requests. Then have three other stores which all will get content from that base store. It is a little dirty, but it would work, and it isn't hard to put together.
    Sencha Inc.
    Robert Dougan - @rdougan
    Sencha Touch 2 and Ext JS 4 Core Team Member, SASS/Theming Wizard.

  4. #3
    Touch Premium Member
    Join Date
    Oct 2011
    Posts
    15

    Default

    So having duplicated data is a better solution than allowing a view to filter data from a single store? C'mon, you even described you're own solution as dirty.

  5. #4
    Sencha User rdougan's Avatar
    Join Date
    Oct 2008
    Posts
    1,159
    Answers
    93

    Default

    I'm just suggesting the best way to do it right now. We have no plans to support this as it isn't a popular requested feature. I've added it to our internal tracking system however and we will review for 2.x.
    Sencha Inc.
    Robert Dougan - @rdougan
    Sencha Touch 2 and Ext JS 4 Core Team Member, SASS/Theming Wizard.

  6. #5
    Touch Premium Member
    Join Date
    Oct 2011
    Posts
    15

    Default

    Quote Originally Posted by rdougan View Post
    We have no plans to support this as it isn't a popular requested feature. I've added it to our internal tracking system however and we will review for 2.x.
    This is a far better response than:

    There is no way to do this in ST2, and we have no plans to support it either.

  7. #6
    Sencha User
    Join Date
    Sep 2011
    Posts
    46
    Answers
    1

    Lightbulb Workaround: FilteredStore

    For now I've created a workaround by creating a FilteredStore class:

    Code:
    Ext.define('gs.store.FilteredStore', {
        extend: 'Ext.data.Store',
    
    
        // Parameters
        sourceStore: '',
        filter: null,
    
    
        // Fields
        sourceStoreEventHooks: {
            load: 'sourceStoreChanged',
            sort: 'sourceStoreChanged',
            filter: 'sourceStoreChanged',
            add: 'sourceStoreChanged',
            remove: 'sourceStoreChanged',
            update: 'sourceStoreChanged',
            clear: 'sourceStoreChanged'
        },
    
    
        // Constructor and initialization
        constructor: function (config) {
            // Check source store parameter
            if (this.sourceStore === undefined || this.sourceStore === '') {
                Ext.Error.raise({ msg: 'No source store provided for this filtered store' });
            }
    
    
            // Listen to source store events and copy model
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) {
                this.model = sourceStore.model;
                sourceStore.on(Ext.apply({}, this.sourceStoreEventHooks, { scope: this }));
            }
    
    
            // Call the parent
            this.callParent(arguments);
        },
        intialize: function () {
            // Call the parent
            this.callParent(arguments);
    
    
            // Simulate source store change to fill this store
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) { this.sourceStoreChanged(sourceStore); }
        },
    
    
        // Methods
        resolveStore: function (storeName) {
            // Resolves a store name via the StoreManager
            if (storeName) {
                var store = Ext.data.StoreManager.lookup(storeName);
                if (store && Ext.isObject(store) && store.isStore) {
                    return store;
                }
            }
    
    
            return null;
        },
    
    
        getFilter: function () {
            // Gets the filter
            return this.filter;
        },
        setFilter: function (filter) {
            // Sets the filter and updates the data
            this.filter = filter;
    
    
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) {
                this.sourceStoreChanged(sourceStore);
            }
        },
    
    
        // Event handlers
        sourceStoreChanged: function (sourceStore) {
            var sourceStoreData = sourceStore.data;
            if (this.filter !== undefined) {
                sourceStoreData = sourceStoreData.filterBy(this.filter);
            }
    
    
            this.data = sourceStoreData;
            this.fireEvent('filter', this);
        }
    });
    You can define a store that inherits FilteredStore and point it to the original store via sourceStore. It has a filter property that accepts a function that will do the filtering for you.

    Feel free to clean the code and add it to the framework
    Of course it needs a lot more exception handling, getter/setter methods etc etc, but it gets the job done for my problem.

  8. #7
    Sencha User luismerino's Avatar
    Join Date
    Oct 2011
    Location
    Berlin
    Posts
    46
    Answers
    1

    Default

    Quote Originally Posted by Zyphrax View Post
    For now I've created a workaround by creating a FilteredStore class:

    Code:
    Ext.define('gs.store.FilteredStore', {
        extend: 'Ext.data.Store',
    
    
        // Parameters
        sourceStore: '',
        filter: null,
    
    
        // Fields
        sourceStoreEventHooks: {
            load: 'sourceStoreChanged',
            sort: 'sourceStoreChanged',
            filter: 'sourceStoreChanged',
            add: 'sourceStoreChanged',
            remove: 'sourceStoreChanged',
            update: 'sourceStoreChanged',
            clear: 'sourceStoreChanged'
        },
    
    
        // Constructor and initialization
        constructor: function (config) {
            // Check source store parameter
            if (this.sourceStore === undefined || this.sourceStore === '') {
                Ext.Error.raise({ msg: 'No source store provided for this filtered store' });
            }
    
    
            // Listen to source store events and copy model
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) {
                this.model = sourceStore.model;
                sourceStore.on(Ext.apply({}, this.sourceStoreEventHooks, { scope: this }));
            }
    
    
            // Call the parent
            this.callParent(arguments);
        },
        intialize: function () {
            // Call the parent
            this.callParent(arguments);
    
    
            // Simulate source store change to fill this store
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) { this.sourceStoreChanged(sourceStore); }
        },
    
    
        // Methods
        resolveStore: function (storeName) {
            // Resolves a store name via the StoreManager
            if (storeName) {
                var store = Ext.data.StoreManager.lookup(storeName);
                if (store && Ext.isObject(store) && store.isStore) {
                    return store;
                }
            }
    
    
            return null;
        },
    
    
        getFilter: function () {
            // Gets the filter
            return this.filter;
        },
        setFilter: function (filter) {
            // Sets the filter and updates the data
            this.filter = filter;
    
    
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) {
                this.sourceStoreChanged(sourceStore);
            }
        },
    
    
        // Event handlers
        sourceStoreChanged: function (sourceStore) {
            var sourceStoreData = sourceStore.data;
            if (this.filter !== undefined) {
                sourceStoreData = sourceStoreData.filterBy(this.filter);
            }
    
    
            this.data = sourceStoreData;
            this.fireEvent('filter', this);
        }
    });
    You can define a store that inherits FilteredStore and point it to the original store via sourceStore. It has a filter property that accepts a function that will do the filtering for you.

    Feel free to clean the code and add it to the framework
    Of course it needs a lot more exception handling, getter/setter methods etc etc, but it gets the job done for my problem.

    ++ I will definitely use this.

    Creating several stores branching off a main one is a pain to keep data consistency. I will give your class a try immediately

  9. #8
    Sencha User luismerino's Avatar
    Join Date
    Oct 2011
    Location
    Berlin
    Posts
    46
    Answers
    1

    Default

    Alright, so in order to use it on my project I have made a few modifications that allow to set up the sourceStore later, not being forced to assign one when defining the filtered store necessarily. This is useful in the case the sourceStore is generated by a hasMany association for instance, in which case it comes in handy.

    Code:
    Ext.define('Extra.data.store.FilteredStore', {
        
        extend: 'Ext.data.Store',
        
        alternateClassName: ['Ext.store.FilteredStore'],
    
    
        // Parameters
        sourceStore: '',
        
        filter: null,
    
    
        // Fields
        sourceStoreEventHooks: {
            load: 'sourceStoreChanged',
            sort: 'sourceStoreChanged',
            filter: 'sourceStoreChanged',
            add: 'sourceStoreChanged',
            remove: 'sourceStoreChanged',
            update: 'sourceStoreChanged',
            clear: 'sourceStoreChanged'
        },
    
    
        // Constructor and initialization
        constructor: function(config) {
            // Check source store parameter
            if (this.sourceStore === undefined || this.sourceStore === '') {
                Ext.Logger.warn('No source store provided for this filtered store', this);
            }
    
    
            // Listen to source store events and copy model
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore !== null) {
                this.model = sourceStore.model;
                sourceStore.on(Ext.apply({}, this.sourceStoreEventHooks, { scope: this }));
            }
    
    
            // Call the parent
            this.callParent(arguments);
        },
        
        intialize: function() {
            // Call the parent
            this.callParent(arguments);
    
    
            // Simulate source store change to fill this store
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore !== null)
                this.sourceStoreChanged(sourceStore);
        },
    
    
        // Methods
        resolveStore: function (store) {
            // Resolves a store name via the StoreManager
            if (store) {
                store = Ext.data.StoreManager.lookup(store);
                if (store && Ext.isObject(store) && store.isStore) {
                    return store;
                }
            }
    
    
            return null;
        },
        
        setSourceStore: function(sourceStore) {
            var sourceStore = this.resolveStore(sourceStore);
            if (sourceStore !== null) {
                this.sourceStoreChanged(sourceStore);
                this.model = sourceStore.model;
                this.sourceStore = sourceStore;
                sourceStore.on(Ext.apply({}, this.sourceStoreEventHooks, { scope: this }));
            }
        },
    
    
        getFilter: function () {
            // Gets the filter
            return this.filter;
        },
        
        setFilter: function (filter) {
            // Sets the filter and updates the data
            this.filter = filter;
    
    
            var sourceStore = this.resolveStore(this.sourceStore);
            if (sourceStore != null) {
                this.sourceStoreChanged(sourceStore);
            }
        },
    
    
        // Event handlers
        sourceStoreChanged: function (sourceStore) {
            var sourceStoreData = sourceStore.data;
            if (this.filter !== undefined)
                sourceStoreData = sourceStoreData.filterBy(this.filter);
    
    
            this.data = sourceStoreData;
            this.fireEvent('filter', this);
        }
    });
    This update it's working fine for me. Thanks a lot again for the idea!

    Here's an example for those who still are in doubt how this works...

    Code:
    Ext.define('My.store.Attending', {
        
        storeId: 'Attending',
        
        extend: 'Extra.data.store.FilteredStore',
        
        model: 'My.model.Attendance',
        
        filter: function(record) {
            return record.get('rsvp_status') === 'attending';
        }
    
    
    });
    
    [...]
    
    var store = Ext.getStore('Attending');
    store.setSourceStore(myHasManyGeneratedStore);

  10. #9
    Sencha User
    Join Date
    Mar 2012
    Posts
    15

    Question with nested data?

    Hello,


    Using the code above, how can I procede if my data is nested ?


    Say I have this JSON data, how can I
    send only the "cats" array to my DataView? :




    Code:
    {
      "animals": [
        {
          "cats": [
            {
              "name": "Fluffy",
              "color": "brown",
              "mood": "happy"
            },
            {
              "name": "Joe",
              "color": "white",
              "mood": "sad"
            }
         }
    }

  11. #10
    Sencha User
    Join Date
    Sep 2011
    Posts
    46
    Answers
    1

    Default

    Luismerino: nice adjustments!

    Junkw:
    To only show the Cats, I would use an if-statement in the Dataviews ItempTpl. You can't filter on Cats via the FilteredStore because that would change your model from Animals to Cats.

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •