Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

underscore methods on Collection return and array of Models (not a Collection) #120

Closed
RandomEtc opened this Issue Dec 6, 2010 · 11 comments

Comments

Projects
None yet
7 participants

I tried to do:

var things = new Backbone.Collection([
    { name: "thing 1", active: false },
    ...,
    { name: "thing n", active: true }
]);
var activeThingNames = things.filter(function(t) { 
    return t.get('active')
}).pluck('name');

But pluck didn't work after filter, because pluck is a method on Collection but filter returns an array of Models. It's not a big deal (I can just use map to get the names) but I'm new to Backbone and wondering if I'm missing something?

Owner

jashkenas commented Dec 6, 2010

Nope -- you're not missing anything. Collection methods do indeed return arrays of models. You can use Underscore.js to re-wrap the array, if you like, and continue to perform collection operations.

var activeThingNames = _(things.filter(function(t) {
  return t.get("active");
})).pluck("name");

http://documentcloud.github.com/underscore/#styles

Very handy, thanks! Big fan of Underscore but I'd missed the wrapper style entirely.

I just tried the above, using _ to wrap the array but _'s version of pluck doesn't know about Backbone Models like Collection's version does. (It would need to call t.get('name') rather than access t.name).

Perhaps a wrapper function like _ but that also knows about Models would be useful?

Owner

jashkenas commented Dec 8, 2010

Ah, yes, pluck is a special case ... I'd use map in conjunction with filter to get the list of active thing names, like you're trying to do. Either that, or .pluck('attributes') and then .pluck('name').

I'm running into a similar issue. The only difference being that I really need to perform collection-specific actions. So, Is there a way to convert the array into a collection?

How comes using the _() we can't run .toJSON() ?

@posabsolute Because wrapping with _() will return an Underscore collection, not a Backbone collection. To get a Backbone collection with all the Backbone methods like .toJSON() available, you have to wrap with new Backbone.Collection() (or whatever collection you're using that inherits from Backbone.Collection) instead of _().

For example, applying this to the OP's code:

var activeThingNames = new Backbone.Collection(things.filter(function(t) { 
    return t.get('active')
})).pluck('name');

Thanks! but i asked that 2 years ago :P

@posabsolute Haha yea, I know. Was just passing through and thought I'd answer for future readers :)

Thanks guys!!!! Very Helpful!!! :)

I'm way late to this party, but I just came across a need for this myself. I extended the Backbone.Collection with my own base collection and added a wrap function like so:

const ExtendedCollection = Backbone.Collection.extend( {
	wrap( method, ...args ) {
		return new this.constructor( this[ method ]( ...args ) );
	},
} );

Usage looks like so:

collection.wrap('map', f => f.set('test', true) )

Cheers to any other Backbone users out there. Maybe not the cleanest syntax, but it does the job with minimal hackery.

This issue was closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment