David Hellsing
David Hellsing

Reputation: 108480

Backbone filtering

If I have a Backbone collection and want to create a copy of that collection with certain entries filtered out, how can I do that while keeping the copied instance as a Backbone.Collection?

Example:

var Module = Backbone.Model.extend();

var ModuleCollection = Backbone.Collection.​extend({
    model: Module
});

​var modules = new ModuleCollection;

​modules.add({foo: 'foo'​​​​​​},{foo: 'bar'});​​​​​

console.log(modules instanceof Backbone.Collection); // true

var filtered = modules.filter(function(module) {
    return module.get('foo') == 'bar';
});

console.log(filtered instanceof Backbone.Collection); // false

http://jsfiddle.net/m9eTY/

In the example above, I would like filtered to be a filtered version of modules, not just an array of models.

Essentially I would like to create a method in the collection instance that can filter out certain models and return the Backbone.Collection instance, but as soon as I start filtering the iteration methods returns an array.

Upvotes: 5

Views: 4411

Answers (2)

Pascal
Pascal

Reputation: 2405

For filtering collection using backbone

To make the filter you should have a filtered function in your collection

var MyCollection = Backbone.Collection.extend ({
  filtered : function () { 

I suggest to use UnderScore filter which will return true for valid and false for invalid where true is what you are looking for. use this.models to get the current collection models use model.get( '' ) to get the element you want to check for

var results = _.filter( this.models, function ( model ) {           
    if ( model.get('foo') == 'bar' ) 
    return true ; 
    return false ;
});

Then use underscore map your results and transform it to JSON like this is probally where you are getting it wrong

results = _.map( results, function( model ) { return model.toJSON()  } );

Finally returning a new backbone collection with only results this is how to make a copied collection

return new Backbone.Collection( results ) ;

Upvotes: 0

Vincent Briglia
Vincent Briglia

Reputation: 3068

You can wrap the filtered array in a temporary ModuleCollection if you want, the models filtered are the same instances of the ones in the original ModuleCollection, so if the module's attribute changes, it is still referenced by both collections.

so what I suggest you do is something like:

var filtered = new ModuleCollection(modules.filter(function (module) {
    return module.get('foo') == 'bar';
}));

Since Backbone 0.9.2 there is an additional method called where that does the same:

var filtered = modules.where({foo: 'bar'});

that still returns an array though, so you will still need to wrap it as such:

var filtered = new ModuleCollection(modules.where({foo: 'bar'}));

Upvotes: 9

Related Questions