The current method I'm using is to filter a collection, which returns an array, and use
collection.reset(array)
to re-populate it. However, this modifies the original collection, so I added an array called "originalCollectionArray" which keeps track of the initial array state of the collection. When no filtering is active I simply use
collection.reset(originalCollectionArray)
But then, I need to keep track of adding and removing models from the real collection, so I did this:
// inside collection
initialize: function(params){
this.originalCollectionArray = params;
this.on('add', this.addInOriginal, this);
this.on('remove', this.removeInOriginal, this);
},
addInOriginal: function(model){
this.originalCollectionArray.push(model.attributes);
},
removeInOriginal: function(model){
this.originalTasks = _(this.originalTasks).reject(function(val){
return val.id == model.get('id');
});
},
filterBy: function(params){
this.reset(this.originalCollectionArray, {silent: true});
var filteredColl = this.filter(function(item){
// filter code...
});
this.reset(filteredColl);
}
This is quickly becoming cumbersome as I try to implement other tricks related to the manipulation of the collection, such as sorting. And frankly, my code looks a bit hacky. Is there an elegant way of doing this?
Thanks
Collections are ordered sets of Models. We just need to extend the backbone's collection class to create our own collection. Any event that is triggered on a model in a collection will also be triggered on the collection directly.
You could create a collection as a property of the main collection reflecting the state of the filters:
var C = Backbone.Collection.extend({
initialize: function (models) {
this.filtered = new Backbone.Collection(models);
this.on('add', this.refilter);
this.on('remove', this.refilter);
},
filterBy: function (params){
var filteredColl = this.filter(function(item){
// ...
});
this.filtered.params = params;
this.filtered.reset(filteredColl);
},
refilter: function() {
this.filterBy(this.filtered.params);
}
});
The parent collection keeps its models whatever filters you applied, and you bind to the filtered collection to know when a change has occurred. Binding internally on the add and remove events lets you reapply the filter. See http://jsfiddle.net/dQr7X/ for a demo.
The major problem on your code is that you are using a raw array as original, instead of a Collection. My code is close to the yours but use only Collections, so methods like add, remove and filter works on the original:
var OriginalCollection = Backbone.Collection.extend({
});
var FilteredCollection = Backbone.Collection.extend({
initialize: function(originalCol){
this.originalCol = originalCol;
this.on('add', this.addInOriginal, this);
this.on('remove', this.removeInOriginal, this);
},
addInOriginal: function(model){
this.originalCol.add(model);
},
removeInOriginal: function(model){
this.originalCol.remove(model);
},
filterBy: function(params){
var filteredColl = this.originalCol.filter(function(item){
// filter code...
});
this.reset(filteredColl);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With