Search code examples
javascriptbackbone.jsbackbone-viewsbackbone.js-collections

How to use the original Backbone collection after filtering?


I'm relatively new to Backbone and though I know the general idea of how to use it, my learning has been rapid and I'm probably missing some key elements.

So I have a collection that contains an attribute called "type" which can be article, book, video, class. I have the view rendering and everything but I need to be able to filter the collection when links are clicked.

My question is - how can I get it to filter down the collection and still be able to refilter the original collection when I click on another type?

Here's the gist of my code, I simplified it for easy reading:

var TagsView = Backbone.View.extend({
    initialize: function(query) {
        this.collection = new TagsCollection([], {query: self.apiQuery} );
        this.collection.on('sync', function() {
            self.render();
        });
        this.collection.on('reset', this.render, this);
    },
    render: function() {
        //renders the template just fine
    },
    filter: function() { 
        //filtered does work correctly the first time I click on it but not the second.
        var filtered = this.collection.where({'type':filter});
        this.collection.reset(filtered);
    }
});

update: I managed to get this working. I ended up triggering a filter event.

var TagsCollection = Backbone.Collection.extend({
    initialize: function(model, options) {
        this.query = options.query;
        this.fetch();
    },
    url: function() {
        return '/api/assets?tag=' + this.query;
    },
    filterBy: function(filter) {
        filtered = this.filter(function(asset) {
            return asset.get('type') == filter;
        });
        this.trigger('filter');
        return new TagsCollection(filtered, {query: this.query});
    },
    model: AssetModel
});

And then in my view, I added some stuff to render my new collection.

var TagsView = Backbone.View.extend({
    initialize: function(query) {
        this.collection = new TagsCollection([], {query: self.apiQuery} );
        this.collection.on('sync', function() {
            self.render();
        });
        this.collection.on('filter sync', this.filterTemplate, this);
        this.collection.on('reset', this.render, this);
    },
    render: function() {
        //renders the template just fine
    },
    filterCollection: function(target) {
        var filter = $(target).text().toLowerCase().slice(0,-1);
        if (filter != 'al') {
            var filtered = this.collection.filterBy(filter);
        } else {
            this.render();
        }

    },
    filterTemplate: function() {
        filterResults = new TagsCollection(filtered, {query: self.apiQuery});
        console.log(filterResults);
        $('.asset').remove();
        filterResults.each(function(asset,index) {
            dust.render('dust/academy-card', asset.toJSON(),     function(error,output) {
                self.$el.append(output);
            });
        });
    },  
});

Solution

  • Here's a better answer to this. Instead of making it so complicated, you can just use the where method. Here's my replacement solution for the question above.

    filterby: function(type) {
          return type === 'all' ? this : new BaseCollection(this.where({type: type});
    });