0

I was investigating a bug and decided to review the jQuery.on() docs to make sure I understood delegated events. I was surprised to read:

Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on().

I was surprised because I'd been binding events to elements not in the DOM, and upon inserting the elements into the DOM, those elements would respond to events that bubbled through!

I was so confused by this statement that even tested my understand of it. You can find this test here: http://jsfiddle.net/eUuv4/.

In summary, I make a Backbone View:

var View = Backbone.View.extend({
    template: _.template('<div class="inner"><button>Say hello</button></div>'),
    initialize: function (options) {
        this.name = options.name;
        this.$el.append($(this.template()));
    },
    events: {
        'click button': function () { 
            console.log('Hello from ' + this.name);
        }
    },
});

And then construct it with two different elements: one that is in the DOM; and one that is not in the DOM when the view is constructed. Upon inserting the second variant into the DOM, as I expected, its element responds to delegated events that pass through it.

So, what are the jQuery docs trying to say with the above quoted statement?

Dmitry Minkovsky
  • 30,036
  • 20
  • 97
  • 138
  • I think it's just poorly worded. It simply means that the element must *exist*. But it doesn't have to be part of the document. – Felix Kling Feb 17 '14 at 02:15
  • @FelixKling Ok, that's what I thought for a secnd, but what's the point of saying that, or even bolding that. How/why would you try to bind an event on a non-existing element? Does this mean people do `$('.i-know-this-doesnt-exist').on('click', function() {});` and expect it to magically bind when the element does exist?? – Dmitry Minkovsky Feb 17 '14 at 02:16
  • I think the sequence of events is not happening the way you think it is. I don't know Backbone, but for the .on() method, only the _selector_ to which the listener is bound must exist. The delegated elements under it do not need to exist when the listener is instantiated. – Jakob Jingleheimer Feb 17 '14 at 02:17
  • @dimadima: Yes. People are selecting the elements of a specific class and wonder why elements with that class, which are created *later* on, don't have that event handler. – Felix Kling Feb 17 '14 at 02:17
  • You are massively confusing backbone and jQuery. Here is a demo showing that .on() only binds to elements that exist at the time of execution: http://jsfiddle.net/Kk3ny/. And the reason you may want to bind elements that don't exist is because they might be created/loaded in the future. – Christian Feb 17 '14 at 02:17
  • @FelixKling: that's crazy. Oh well! Hah! :D – Dmitry Minkovsky Feb 17 '14 at 02:18
  • Example: http://stackoverflow.com/q/12829963/218196 – Felix Kling Feb 17 '14 at 02:19
  • I think backbone is using event delegation to handle the events... http://jsfiddle.net/arunpjohny/tCP23/1/ - because an element which was created after the rendering of the main view also is firing the event – Arun P Johny Feb 17 '14 at 02:19
  • "As of jQuery 1.7, the .on() method provides all functionality required for attaching event handlers." – Anthony Feb 17 '14 at 02:19
  • Yes, my example/fiddle unfortunately requires knowing that Backbone uses `$.fn.on()` and delegates. Anyway, thanks for clarifying, @FelixKling – Dmitry Minkovsky Feb 17 '14 at 02:20
  • I might be wrong, but what backbone does seems to be irrelevant here. The op could also have asked why does `$('
    ').on('click', ...)` works even thought the element is not "in the DOM". That's why I avoid the phrase "in the DOM" and use "document" instead.
    – Felix Kling Feb 17 '14 at 02:21
  • Yes, when I read "they must exist on the page" I interpret this to mean `element.parentNode` is not null or a document fragment. – Dmitry Minkovsky Feb 17 '14 at 02:23

1 Answers1

1

I think it's just poorly worded. It simply means that the element must exist at the moment the handler is bound.

Whether the element is part of the document or whether you created it programmatically (and haven't added it to the document yet) doesn't matter.


How/why would you try to bind an event on a non-existing element?

I think it's partly jQuery's fault, because it made things so easy / provided such a high level abstraction. People starting with jQuery often don't have any idea how event handling in JavaScript actually works.

The existence of the (now deprecated) .live method also contributed to this misconception. I mean, if you see

$('.foo').live('click', ...);

then it's only a small step to believe that jQuery always, magically, handles every element with that class, whether it exists now or in the future.

Introducing .on was a step in the right direction to "demystify" jQuery.

Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072