How do I convert a filtered collection to JSON with Backbone.js?
So I have a collection in Backbone for a list of events. This collection has a method on it which filters the list based on a list of categories passed to it.
var Events = Backbone.Collection.extend({
model: Event,
url: settings.events_url,
filtered: function(checked) {
return this.filter(function(e) {
if ($.inArray(e.get('category').name, checked) >= 0) {
return true;
} else {
return false;
}
});
}
});
What I need to be able to do is convert this filtered collection to JSON, the same way you would do the collection as a whole.
var events = new Events();
events.toJSON();
However, because the filtered collection is no longer an actual collection, but rather a list of models, I don't have the .toJSON() method available to me. Is there a way to convert my filtered collection to a real collection? Or is there an easier way to convert it to JSON?
Th开发者_JS百科anks!
The constructor for a collection can take a list of models as an argument so:
var events = new Events();
var filteredEvents = new Events(events.filtered(true));
console.log(filteredEvents.toJSON());
Why not make use of the standard API?
var checked = ['foo', 'bar', 'baz'],
filtered = eventsCollection
.chain()
.filter(function(model) {
return _.include(checked, model.get('category').name);
})
.invoke('toJSON')
.value();
On a separate note, Events.filterByCategoryName
method name is more explicit. However, I tend not to implement too many 'convenient' methods in my design and embrace the standard API by using them directly.
You could also try something like:
filtered: function(checked) {
return _.map(this.filter(function(e) {
return $.inArray(e.get('category').name, checked) >= 0
}), function(model) {
return model.toJSON();
});
}
Starting from the inside out:
- The call to this.filter will return the list of filtered results as you had it already.
- The _.map will perform an action on each entry of the array it is passed (it simply returns the result of model.toJSON()).
You can do like so :
var myFilteredCollection = new Events();
_.each(myFilteredData, function(eventModel){
myFilteredCollection.add(eventModel);
});
myFilteredCollection.toJSON();
The way I solved it is running a reduce
function on the collection. The advantage of this is that you only do a 1 pass on the collection itself, remembering only the valid models, and returning the JSON of the model if they pass validation.
The other solutions offered to build a new collection which is performance wise - terrible.
getValidItems: function () {
//return only valid items as json
return this.collection.reduce(function (validItems, row) {
if (row.isValid()) {
validItems.push(row.toJSON());
}
return validItems;
}, []);
},
//somewhere where you save
save: function() {
var validItems = this.getValidItems();
//do something with valid items
}
精彩评论