There has to be something simple I am missing here.
http://jsfiddle.net/v9mdZ/
I am just learning Backbone and Underscore/loDash and am trying to get familiar with chain
.
I have the following code, which works as expected:
var ids = _.pluck(collection.where({'is_checked':true}), 'id');
I attempted to refactor this, using chain
like so:
var ids = collection.chain().where({'is_checked':true}).pluck('id').value();
Why doesn't the refactored code work? Am I using chain
wrong?
Solution (details below)
Don't use where
with chain
.
The merging of some Underscore methods into collections is a little imperfect. When you say collection.some_mixed_in_underscore_method()
, the collection unwraps some of the Backbone stuff behind your back so that the Underscore method is applied to the attributes inside the collection's models; it sort of works like this:
var ary = _(this.models).map(function(m) { return m.attributes });
return _(ary).some_mixed_in_underscore_method();
But collection.chain()
doesn't work like that, chain
just wraps the collection's models
directly so if you do this:
console.log(collection.chain());
you'll see that chain
is giving you an object that wraps an array of models. Your models won't have an is_checked
property (i.e. there is no model.is_checked
), they will have is_checked
attributes though (i.e. there will be model.get('is_checked')
and model.attributes.is_checked
).
Now we can see where everything goes wrong:
collection.chain().where({'is_checked':true})
The models don't have is_checked
properties. In particular, there won't be any models where is_checked
is true
and everything after the where
is working with an empty array.
Now that we know where things go sideways, how do we fix it? Well, you could use filter
instead of where
so that you can easily unpack the models:
collection.chain()
.filter(function(m) { return m.get('is_checked') })
.pluck('id')
.value();
But, your models don't have id
s yet as you didn't create them with id
s and you haven't talked to a server to get id
s so you're going to get an array of undefined
s back. If you add some id
s:
var collection = new App.OptionCollection([
{id: 1, 'is_checked': true},
{id: 2, 'is_checked': true},
{id: 3, 'is_checked': false}
]);
then you'll get the [1,2]
that you're looking for.
Demo: http://jsfiddle.net/ambiguous/kRmaD/