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?

- 4,188
- 3
- 34
- 50
-
I haven't used Backbone, so a comment rather than an answer: It looks like Backbone collections are JavaScript objects (hard to imagine what else they would be), which means that unless they're `sealed` (a new ECMAScript5 thing), you can just add properties to them if you like in the normal way: `instance.prop = value;`. Naturally you have to be careful not to use names that conflict with anything that already exists on the object... – T.J. Crowder May 08 '11 at 22:10
-
The answer is completely dependant on what kind of meta information it is. Depending on what your storing it might fit on the collection or on the view. – Raynos May 08 '11 at 22:33
-
@T.J. Crowder - I could do that, but it has a lot of potential problems. Having a dedicated Object just for attributes means that you can be much safer, I think. – idbentley May 08 '11 at 23:17
-
I would create an object that would have the collection as a property. – Julien Sep 07 '12 at 14:36
5 Answers
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.

- 166,823
- 56
- 351
- 396
-
Thanks for that - helps a lot. Your last point highlights something I've been wanting to do as well... I'll ask another question regarding that though, as your answer here is exactly what I've been wanting. – idbentley May 08 '11 at 23:18
-
@idbentley if you highlight exactly what your meta data that needs to be persistantly stored is I can point you in the right direction. – Raynos May 08 '11 at 23:23
-
I asked a new question here with details: http://stackoverflow.com/questions/5931898/persisting-loading-metadata-in-a-backbone-js-collection – idbentley May 09 '11 at 02:26
-
Is this ever worked? I didn't succeed in getting the meta value. It's always undefined. What is the format of the value? Is collection.meta("id", 1) will work? – yves amsellem May 30 '11 at 12:48
-
20It turns out that this isn't really the best way to do this. Instead, wrap the collection in a model. In fact, if I had read the documentation carefully at the time I would have known this as they give an example of it here: http://documentcloud.github.com/backbone/#FAQ-nested . The meta information lives in the wrapping model. This should help. – idbentley Jun 03 '11 at 19:48
-
@yvesamsellem well spotted there was a bug with it. It's supposed to be `===` not `!==` – Raynos Jun 03 '11 at 20:07
-
1The `meta` function is not contributing much. You could have used the _meta directly (`view._meta.a = 'b'` and `var c = view._meta.a`). Other than that, @idbentley's comment is a better solution. – Tal Bereznitskey Sep 08 '13 at 15:20
-
@TalBereznitskey is there ANY reason not to do that? Seems so unnecessary. @idbentley how would one access the attributes of the collection model in that case? Don't I still end up sticking attributes right on the collection? I could assign `collection.model = this` when I create the collection inside the outer model so I can get back to it from the child model by doing `childModel.collection.model` – light24bulbs Nov 13 '14 at 06:50
-
@idbentley I keep hearing people say that, but honestly I'm tired of creating another model and layer of abstraction just to provide simple attributes (usually 'ID', 'fetching' (for showing loading indicators), and 'synced'). Having to create another model "in the middle" just adds unnecessary complexity and code. It's perfectly logical for collections to have attributes as well as models - for example, a playlist can have a name and and ID that identify it as well as the set of tracks. While that can be worked around with a "metamodel" it seems like that should be completely unnecessary. – Isochronous Jun 30 '15 at 20:24
-
"While that can be worked around with a "metamodel" it seems like that should be completely unnecessary. " - I understand why you feel that way, but the architecture of Backbone isn't designed this way. It may feel like a cleaner pattern, but you will bump against the framework (esp when trying to populate this metadata remotely) at each step. The level of indirection can indeed be frustrating, but it has saved me time in the long run. – idbentley Jul 01 '15 at 21:00
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.

- 10,181
- 7
- 62
- 98

- 7,844
- 8
- 49
- 62
-
1Thanks for the better answer. I posted a seperate question which made this obvious to me. http://stackoverflow.com/questions/5931898/persisting-loading-metadata-in-a-backbone-js-collection I encourage anyone to read the conversation in that question; I found it very clarifying. – idbentley Sep 20 '14 at 15:10
-
-
The OP's question seems important for things like API keys, user ids, etc. that are necessary to construct the url used by fetch(). – elplatt Jul 17 '18 at 19:06
-
In the above example, let's say I have a Book view that should also show the address this book is currently located. How would you do that? Something like `this.model.collection.owner.address` ? I don't like it much. – oriadam Jul 30 '19 at 08:44
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);
}
}
// ...
});

- 71
- 1
- 2
-
1Have a look at this question for an alternative. Essentially, wrapping the collection in a model allows a lot more flexibility without hacking a lot of cruft into the collection. http://stackoverflow.com/questions/5931898/persisting-loading-metadata-in-a-backbone-js-collection – idbentley May 14 '12 at 15:47
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.

- 7,106
- 5
- 44
- 68
-
3The reason why it didnt work was because there was a bug. `!==` instead of `===` – Raynos Jul 05 '11 at 18:03
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.

- 19,094
- 7
- 58
- 72
-
This works well Madbreaks, no doubt. The reason that I avoided this solution was because I wanted to be able to use `fetch` with no modifications. Check out this question, which explains what I'm saying in more detail: https://stackoverflow.com/questions/5931898/persisting-loading-metadata-in-a-backbone-js-collection – idbentley Dec 10 '20 at 23:41