Setting attributes on a collection - backbone js
Collections in backbone js don't allow you to 开发者_运维知识库set
attributes, but I often find that there is need to store some meta-information about a collection. Where is the best place to set that information?
Just .extend
the collection with a meta data storage function.
var MyCollection = Backbone.Collection.extend({
initialize: function() {
...
this._meta = {};
},
model: ...
meta: function(prop, value) {
if (value === undefined) {
return this._meta[prop]
} else {
this._meta[prop] = value;
}
},
});
var collection = new MyCollection();
collection.add(someModels);
collection.meta("someProperty", value);
...
var value = collection.meta("someProperty");
There may be better places for storing specific meta data but this depends completely on what the meta data is.
For storing generic meta data extending your collection constructor with a method to do deal with that should work.
Be wary that if this meta data needs to be stored and loaded from the server then you've got a bigger task at hand.
It's probably best to use Collection in exactly the way it was intended: as a bundle of models. (Julien already commented this on the OP, I'd like to give an explanation why I think he is right)
Let's say you are thinking of a Library (collection) of Book (model) as in Backbone's documentation examples. It makes sense that you've got meta information about the library which you want to store, like the address where this book library is located.
The trick is not to think of it as meta information. You've got a library that has a lot of properties, and one of those properties is its collection of books.
var Book = Backbone.Model.extend({
title: "Moby Dick"
});
var Collection = Backbone.Collection.extend({
model: Book
});
var Library = {
address: '45th Street',
collection: Collection
};
In this example I've defined Library as a plain JavaScript object. Obviously you can also make Library be a model, so that it has all the Backbone bells and whistles. My point here is that you need to represent reality in a more realistic way by taking one step back and seeing that extra properties that you want to assign to the Collection are in fact sibling properties of an object one level up: the Library in this case.
I've upgrated Raynos's approach with event triggering, so we can bind to collection's attributes update.
cls.groups = Backbone.Collection.extend({
// ...
// Reference to this collection's model.
model: cls.group,
initialize: function() {
this._attributes = {}
},
// Extend collection with ability to store attributes and trigger events on attributes changing
attr: function(prop, value) {
if (value === undefined) {
return this._attributes[prop]
} else {
this._attributes[prop] = value;
this.trigger('change:' + prop, value);
}
},
// ...
});
cls.group = Backbone.View.extend({
// ...
initialize: function() {
// Catching attribute update
app.groups.on('change:selected', function(value) {
// ...
}, this);
},
// ...
events: {
'click' : function(e) {
// Set collection meta attribute on model's view click event
app.groups.attr('selected', this.model.cid);
}
}
// ...
});
Using the function meta
of @Raynos solution with only one parameter do not worked for me. So I've used the following code:
var MyCollection = Backbone.Collection.extend({
initialize: function() {
this._meta = {};
},
put: function(prop, value) {
this._meta[prop] = value;
},
get: function(prop) {
return this._meta[prop];
}
});
var collection = new MyCollection();
collection.put("someProperty", 12);
alert(collection.get("someProperty"));
Hope it'll helps.
I've read the other answers and comments and while I appreciate the notion that wrapping a collection in a model might be the absolute cleanest way to a go, I find it absolute overkill 99.9% of the time. Backbone provides the initialize
hook for IMO this exact purpose.
const FooCollection = Backbone.Collection.extend({
initialize: function(models, attributes) {
attributes.log && console.log('foo!'); // Or set attributes on 'this', etc
}
});
// Passing null for first arg, which is optionally an array of models
// to initialize the collection with
const fooCollection = new FooCollection(null, { log: true } );
Been doing this for years and have never encountered any issues/drawbacks.
精彩评论