Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I attach 2 handlers to the same event?

Tags:

I can attach handlers to Backbone Views like:

var TodoView = Backbone.View.extend({     events: {         "xxx": "eventHandler1"         "yyy": "eventHandler2"     } }); 

But what if I want to attach more than 1 handler to the same event?

var TodoView = Backbone.View.extend({     events: {         "xxx": "eventHandler1"         "yyy": "eventHandler2"         "xxx": "eventHandler3" // this isn't valid ... at least in CoffeeScript     } }); 

I could create a custom handler like

function compositeXXX() { eventHandler1(); eventHandler2 } 

But this doesn't seem ideal ...

like image 644
jm2 Avatar asked Jun 06 '12 06:06

jm2


People also ask

How do you attach multiple listeners to the same event?

The addEventListener() method You can add many event handlers of the same type to one element, i.e two "click" events. You can add event listeners to any DOM object not only HTML elements. i.e the window object. The addEventListener() method makes it easier to control how the event reacts to bubbling.

Can we have more than one event handler method for same event?

One event can have more than one event handler method in the same class or in different classes. At the run time only one handler method will be triggered at a time. After triggering the one that has to be deactivated and then another handler method will have to be registered to be triggered.

Can you have multiple click handlers?

Both handlers will run, the jQuery event model allows multiple handlers on one element, therefore a later handler does not override an older handler. The handlers will execute in the order in which they were bound.


2 Answers

This:

events: {     "xxx": "eventHandler1",     "yyy": "eventHandler2",     "xxx": "eventHandler3" } 

won't work because events is an object literal and you can have at most one (key,value) pair in an object. That would probably be the same as saying:

events: {     "xxx": "eventHandler3",     "yyy": "eventHandler2" } 

This CoffeeScript:

events:     "xxx": "eventHandler1"     "yyy": "eventHandler2"     "xxx": "eventHandler3" 

is functionally identical to the JavaScript version and won't work for the same reason.

Andy Ray's idea of using

'event selector': 'callback1 callback2'` 

won't work either as Backbone won't understand that it should split the value on whitespace; similarly, this:

'event selector': [ 'callback1', 'callback2' ] 

won't work because Backbone doesn't know what to do with an array in this context.

Views bind their events through delegateEvents and that looks like this:

delegateEvents: function(events) {   // Some preamble that doesn't concern us here...   for (var key in events) {     var method = events[key];     if (!_.isFunction(method)) method = this[events[key]];     if (!method) throw new Error('Method "' + events[key] + '" does not exist');     // And some binding details that are of no concern either...   } } 

So method starts out as the value for 'event selector'. If it is a function from something like:

'event selector': function() { ... } 

then it is used as-is, otherwise it is converted to a property of this:

method = this[events[key]]; // i.e. method = this[method] 

If one were bold, one could adjust delegateEvents to understand an array or whitespace delimited string:

// Untested code. var methods = [ ]; if (_.isArray(method))   methods = method; else if (_.isFunction(method))   methods = [ method ]; else   methods = method.split(/\s+/); for (var i = 0; i < methods.length; ++i) {   method = methods[i];   if (!_.isFunction(method))     method = this[method];   // And the rest of the binding stuff as it is now with a possible adjustment   // to the "method does not exist" exception message... } 

A fairly simple patch like that would allow you to use a whitespace delimited list of handlers:

'event selector': 'callback1 callback2' 

or an array of handlers:

'event selector': [ 'callback1', 'callback2' ] 

or even a mixed array of method names and functions:

'event selector': [ 'callback_name1', function() { ... }, 'callback_name2' ] 

If you don't want to patch your Backbone or forward such a patch to the Backbone maintainers then you could go with your original "manual dispatching" idea:

'event selector': 'dispatcher' //... dispatcher: function(ev) {     this.handler1(ev);     this.handler2(ev); } 
like image 177
mu is too short Avatar answered Oct 22 '22 10:10

mu is too short


I solved this issue by using jQuery's event namespaces

var TodoView = Backbone.View.extend({     events: {         "xxx.handler1": "eventHandler1",         "yyy": "eventHandler2",         "xxx.handler3": "eventHandler3"     } }); 

This isn't what event namespaces were originally intended for, but as long as they don't clash with other namespaces it shouldn't cause a problem.

The main issue is just that you can only have one value per key in an object and this makes the keys unique.

like image 31
Jiaaro Avatar answered Oct 22 '22 11:10

Jiaaro