简体   繁体   中英

Filtering Backbone.js collection

I'm working with several backbone collections and sometimes I need to access parts of them based on some criteria.

METHOD 1

As already stated in this question , using filter() on the collection itself returns an array of models and not another collection. This can work in simple cases, but it has the effect of losing collection's method concatenation as a plain array of models won't have all methods defined in the collection.

METHOD 2

The answer to that question suggested creating a new collection passing the array of models to the constructor. This works but has the side effect of calling the collection's constructor every time, so any event binding that might be defined there gets stacked on every time you filter the collection.

So what's the correct way to create a sub-collection based on some filter criteria?

Should I use method 1 and create more filtering methods instead on relying on method chaining?

Should I go with method 2 and avoid binding events in the collection's constructor?

Personally I would create more filtering methods on the collection, because it has the additional benefit of encapsulating logic inside the collection.

You could also try to reuse the existing collection. I was toying around with the idea, and arrived at something like this:

var Collection = Backbone.Collection.extend({
  //Takes in n arrays. The first item of each array is the method you want
  //to call and the rest are the arguments to that method. 
  //Sets the collection.models property to the value of each successive filter
  //and returns the result of the last. Revers the collection.models to its original value.
  chainFilters: function(/*args..*/) {
    var models = this.models;
    try {
      filters = _.toArray(arguments);
      _.each(filters, function(filter) {
         this.models = filter[0].apply(this, _.rest(filter));
      }, this);
    } catch(err) {
      this.models = models;
      throw err;
    }

    var filtered = this.models;
    this.models = models;
    return filtered;   
  }
});

Usage:

var results = collection.chainFilters(
  [ collection.filter, function(model) { return model.get('name') === 'foo'; } ],
  [ collection.someMethod, 'someargument' ],
  [ collection.someOtherMethod ]
);

Here's a working sample. It's a bit peculiar, I know.

It depends on the use case. If you want those models to update a view then you probably want a new collection as otherwise you don't get the nice reactive template updates. If you simply wanted the models to iterate through or manipulate data without worrying about the data updating then use the array + underscore.js.

Try it with the arrays and if you find yourself writing a lot of boiler plate code with features already in a collection but not in underscore.js, just start using a collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM