cantera
cantera

Reputation: 24985

Remove Models from Collection Being Filtered

I'm filtering a Backbone collection by running it through an _.each() loop and removing items if they don't fit certain criteria.

For some reason, the loop always stops after filtering about half the collection.

I have two theories:

Here's a working version: http://jsfiddle.net/aZ9zJ/. Can someone tell me what's going on?

--

By the way, I know about filtering functions like _.filter() and _.where() but prefer to avoid them because they return an array rather than a collection.

I'm open to switching over to a filtering function instead, but would still like to understand why the each/remove technique I'm trying doesn't work.

App.View.Items = Backbone.View.extend({
    tagName: 'p',

    initialize: function() {
        Backbone.on('filter:now', this.filterItems, this);

        this.filtered = new Backbone.Collection;

        this.collection.each(function(item) {
            this.filtered.add(item);
        }, this);

        this.filters = new Backbone.Collection([
            {
                property: 'director',
                criteria: 'Orson Welles'
            }
        ]);

        Backbone.trigger('filter:now');
    },

    filterItems: function() {
        this.filters.each(function(filter) {
            this.filtered.each(function(item) {
                if ( item.get(filter.get('property')) === filter.get('criteria') ) {
                    this.filtered.remove(item);
                }
            }, this);
        }, this);

        console.log(this.filtered);
    }

});

Unfiltered collection:

var itemCollection = new App.Collection.Items([
    {
        title: 'Citizen Kane',
        director: 'Orson Welles'
    },
    {
        title: 'Touch of Evil',
        director: 'Orson Welles'
    },
    {
        title: 'The Third Man',
        director: 'Orson Welles'
    },
    {
        title: 'Jaws',
        director: 'Steven Spielberg'
    },
    {
        title: 'Magnificent Ambersons',
        director: 'Orson Welles'
    }
]);

Instantiate view:

var itemsView = new App.View.Items({ collection: itemCollection });

Upvotes: 0

Views: 126

Answers (1)

pawel
pawel

Reputation: 36965

By the way, I know about filtering functions like _.filter() and _.where() but prefer to avoid them because they return an array rather than a collection.

But you should use them none the less.

Messing with the collection being filtered changes its length, so the results may be unpredictable. You should filter your collection and then set the array returned from this operation on your other collection.

this.filtered.set( this.collection.filter(function(item) {
            return item.get(filter.get('property')) === filter.get('criteria');
            }
))

http://jsfiddle.net/aZ9zJ/1/

Upvotes: 1

Related Questions