14

First of all, I did some search and no answer on stackoverflow/google provided me the thing I wanted.

Here's a snippet of my code:

//in the view
this.collection.on("add",triggerthis)
this.collection.add(predefinedModel)
triggerthis: function(a, b, c, d){
    //etc.
}

Basically, I want to be able to pass an argument on add and receive the argument in triggerthis. Is this possible?

Thanks in advance.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
chenglou
  • 3,640
  • 2
  • 25
  • 33
  • 1
    Since the `triggerthis` event handler will be called by the backbone event code, where do you expect those extra argument will come from? – Juan Enrique Muñoz Zolotoochin Jun 24 '12 at 00:42
  • Sorry but I'm not sure how this works. I suppose I can call an anonymous function in on() that calls triggerthis inside, but I'm not sure if this is the good way to proceed. – chenglou Jun 24 '12 at 01:23

2 Answers2

30

You can't do this the way you want without using undocumented features.

If we have a look at Collection#add, we'll see this:

add: function(models, options) {
  //...
  for (i = 0, l = add.length; i < l; i++) {
    (model = add[i]).trigger('add', model, this, options);
  }
  //...
}

Note the fourth argument to trigger. And if we look at the documented interface for trigger:

trigger object.trigger(event, [*args])

Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks.

So the add will call the listeners as f(model, collection, options) where options is the same options what you passed to Collection#add. The result is that if you do this:

this.collection.add(predefinedModel, { undocumented: 'arguments' })

then you could do this in your callback:

triggerthis: function(model, collection, options) {
    console.log(options.undocumented);
}

Demo: http://jsfiddle.net/ambiguous/bqWwQ/

You could of course tunnel a whole array or object through options this way.

The third argument for "add" events isn't documented (at least not that I can find), the closest thing to documentation for this is a note in the 0.3.3 Changelog entry:

The ubiquitous options argument is now passed as the final argument to all "change" events.

I wouldn't recommend this approach but it is there if you need it; you will of course need to cover this in your test suite and you'll need to make sure you don't use any keys in options that Backbone will be using.


A safer approach would be to attach some extra properties to the model:

model.baggage = { some: 'extra stuff };

and then peel that off in the callback:

triggerthis: function(model, collection) {
    var baggage = model.baggage;
    delete model.baggage;
    //...
}

Demo: http://jsfiddle.net/ambiguous/M3UaH/

You could also use different callbacks for different purposes or pass your extra parameters as full blown model attributes.

There's also _.bind:

this.collection.on("add", _.bind(function(collection, model, extra) { ... }, context, collection, model, 'whatever you want'));

but that will bind arguments from left to right so you'll have to specify all the arguments that your callback will need.

Demo: http://jsfiddle.net/ambiguous/jUpJz/

mu is too short
  • 426,620
  • 70
  • 833
  • 800
6

If the values passed to the function are always the same, you can partially apply it using _.bind (or the native Function.bind if available)

E.g. Where you're binding the handler to add (assuming triggerThis is a method in your view):

this.collection.on('add', _.bind(this.triggerThis, this, a, b, c, d));

The definition of triggerThis:

triggerThis: function(a, b, c, d /*, model, collection, options - if you need them*/) {
  ...
}

If you want to pass arguments to an individual add call, you can use the second options parameter to add and then handle that in your event handler.

E.g.

this.collection.on('add', this.triggerThis, this);
this.collection.add(model, {
  someCustomValue: 'hello';
});

Then in your handler:

triggerThis: function(model, collection, options) {
  var val = options.someCustomValue;
  ...
}
jimr
  • 11,080
  • 1
  • 33
  • 32
  • The problem is that the third `options` argument isn't exactly documented. – mu is too short Jun 24 '12 at 01:50
  • True, though in one of the changelog entries (for 0.9.0) it mentions that "Within a collection's add and remove events, the index of the model being added or removed is now available as options.index." so I assume it's probably not going away anytime soon. – jimr Jun 24 '12 at 01:58
  • The `options` argument to the callbacks is sort of a gray area, the docs sort of talk around it without coming right out saying that it is there. I suspect that it will get legitimatized at some point. I just though it was worth mentioning that there are some caveats. – mu is too short Jun 24 '12 at 02:10