Overriding Backbone.View delegateEvents so that an event object can include mobile events

I am using Hammer.js to capture touch screen events in Backbone View mode. Hammer has a special syntax for adding touch listeners, which I used in the View initialization function:

$("#next-button").hammer({prevent_default: true}).on('tap', $.proxy(this.next, this)); 

I would prefer to add it to the standard event object, for example:

 events: {"tap #next-button":"next"} 

So, I hacked the end of the Backbone.View delegateEvents method:

 var isMobileEvent=["tap", "doubleTap"].indexOf(eventName)!=-1; if (selector === '') { if (isMobileEvent){ this.$el.hammer({prevent_default: true}).on(eventName, method); } else { this.$el.on(eventName, method); } } else { if (isMobileEvent){ this.$el.hammer({prevent_default: true}).on(eventName, selector, method); } else { this.$el.on(eventName, selector, method); } } 

It works great. But when I tried to override the method in one view where it was necessary to override (I was worried that I would forget about this hack in Backbone or overwrite it with a new version of Backbone, etc.), DelegateEvents for my view stopped working. The problem is that method callback method is not recognized as method:

 if (!_.isFunction(method)) method = this[events[key]]; 

Why? I literally copied and pasted the function into a subclass of View. Here is the whole delegate that works in Backbone, but not in my Backbone.View:

 delegateEvents: function(events) { if (!(events || (events = _.result(this, 'events')))) return; this.undelegateEvents(); 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'); var match = key.match(delegateEventSplitter); var eventName = match[1], selector = match[2]; method = _.bind(method, this); eventName += '.delegateEvents' + this.cid; var isMobileEvent=["tap", "doubleTap"].indexOf(eventName)!=-1; if (selector === '') { if (isMobileEvent){ this.$el.hammer({prevent_default: true}).on(eventName, method); } else { this.$el.on(eventName, method); } } else { if (isMobileEvent){ this.$el.hammer({prevent_default: true}).on(eventName, selector, method); } else { this.$el.on(eventName, selector, method); } } } 

CORRECTION:

Replace this line:

 var match = key.match(delegateEventSplitter); 

with this:

 var match = key.match(/^(\S+)\s*(.*)$/); 
0
source share
1 answer

This jsbin shows how you can override the default Backbone View logic for delegateEvents .

You can easily expand it as needed to handle Hammer.JS, as you did above, to extend the Backbone to support various touch events.

I needed to copy the delegateEventSplitter value locally since it was declared confidential (inside closure) inside the Backbone library. Only functions that were executed / returned in the context of this variable have access to this value. Since your new class is not running in this context, it cannot directly access the value.

Relevant Code:

 var SampleView = Backbone.View.extend({ events: { "click" : '_clicked' }, delegateEvents: function(events) { if (!(events || (events = _.result(this, 'events')))) return; this.undelegateEvents(); 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'); var match = key.match(/^(\S+)\s*(.*)$/); var eventName = match[1], selector = match[2]; method = _.bind(method, this); eventName += '.delegateEvents' + this.cid; if (selector === '') { this.$el.on(eventName, method); } else { this.$el.on(eventName, selector, method); } } }, render: function() { this.$el.html("hi"); return this; }, _clicked: function() { alert("clicked!"); } }); // assumes there an element with an id of "content" $(function() { var view = new SampleView(); $("#content").append(view.render().$el); }); 
+1
source

Source: https://habr.com/ru/post/913814/


All Articles