8

I'm using Backbone.js and sometimes the views events do not get bound correctly.

I can check the event binding situation with $(viewselector).data() in jQuery. Most of the time there are events, sometimes there aren't!

Are there any known things I should watch out for that can cause this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
FriiSource
  • 321
  • 2
  • 6
  • 12
  • Can you please post more details and possibly some code as well? Also, what is your javascript load order? You need to make sure that jQuery/Zepto is loaded before underscore and backbone. – Andrew De Andrade Feb 26 '11 at 17:31
  • @Andrew thanks for your help, jQuery is loaded before us/backbone. – FriiSource Feb 26 '11 at 19:19

2 Answers2

16

Events are delegated to this.el when the view is initialized. So you need to:

  • Create the view by giving the constructor the "el" option to specify the element
  • Define el, tag, id, classname on your view to create or find on the page your element directly.
  • Append your rendered view to the "el" element of the view
  • Make sure you do not replace the "el" element after the view creation

For the last item, if you have to do it, you can call delegateEvents once more to re-delegate the event on your view.

Shard
  • 3,175
  • 6
  • 30
  • 40
Julien
  • 9,216
  • 4
  • 37
  • 38
  • 4
    The `events: {}` block in Backbone.js uses jQuery's .delegate() function, which is just a special form of the .live() function, which is itself a special form of the .bind() function that can be declared before a DOM element exists. It shouldn't be necessary to define the "el" attribute to get the elements to work, since backbone.js will either user tagName or give you a div by default. – Andrew De Andrade Feb 26 '11 at 17:29
  • Right, the auto generated div is there and not overwritten, it's what I'm looking at to check whether or not it has the event bound. When it does have an event object, it shows me in firebug the events bound to the el. I presume these can be bubbled to from child elements. But sometimes the event object doesn't exist after loading. Firebug doesn't even show any errors. How do I call delegateEvents? Is it just this.delegateEvents ? or something else. – FriiSource Feb 26 '11 at 19:18
  • 1
    @Andrew what is was explaining is that you should not re-assign this.el because you will then loose that delegation magic. So in the case where you already have an element on the page, you must pass it aqs an option to the view to have the delegation working. – Julien Feb 28 '11 at 00:56
  • 1
    @friisource yes this.delegateEvents(). The other thing you can check is pretty obvious:are the selectors selecting anything once your view is rendered. Also the delegation works by adding events to the base element ( live works with events on body for example) and relies on the propagation of events. So if you el.delegate('click', 'button') the event will be bound to el and when the event bubble up to this element jquery will check for a match of 'button' on the target element. – Julien Feb 28 '11 at 01:02
  • @Julien ahhh... good point. However, when would you want to reassign the element of a view? I can't think of a case when you'd want to do that. – Andrew De Andrade Mar 04 '11 at 01:59
  • thanks for the clarification, i had to assign live events outside the .el element and was wondering why it wasn't working! – fluxsaas Feb 27 '12 at 13:40
  • Just needed to call `delegateEvents` again because I'd replaced the el. Boom, thanks. – earl3s Mar 01 '16 at 01:38
12

My approach in these scenarios is to add delegateEvents() in render of each view that has an event, like the following:

  $(this.el).empty();
  $(this.el).html(this.template({}));
  this.delegateEvents(); // this will bind all events ONCE AGAIN

This is perfect for views specially created dynamically i.e. views that are declared new under each click or so...

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Varand Pezeshkian
  • 520
  • 2
  • 11
  • 22
  • 3
    eek...take care you are not leaking event bindings. i think this will happen if you are repeatedly binding (delegateEvents-ing) but not unbinding previous bindings. – aaron Dec 13 '12 at 21:12
  • 1
    @aaron `html` calls `empty` ["which unbinds all jQuery events on all child nodes"](http://ianstormtaylor.com/rendering-views-in-backbonejs-isnt-always-simple/). You need to call `delegateEvents` in this situation every time, or use `setElement` (see the article). – ian Sep 19 '13 at 09:43
  • also, `delegateEvents` calls `undelegateEvents` before delegating the `events` hash. – Emile Bergeron Nov 23 '16 at 21:32
  • using `view.remove()` will call `Events.stopListening` – hatenine Jan 17 '17 at 20:12