replacing jquery.live() with jquery.on() doesn't work
Asked Answered
A

3

30

I have several textboxes that are added dynamically after an ajax call. These boxes are tied to event handlers with .live() that currently work fine. I want to replace that with the newer .on() function.

This is what I have

$('.MyTextBox').live({
  mouseenter: function () { .... },
  mouseleave: function () { .... },
  blur: function () { ... }
});

When I replace .live() with .on() it doesn't work; the textboxes don't display their normal behavior after they're added.

If I write $('#MainDiv .MyTextBox').live({... , where MainDiv is the top DOM element where all the action happens, nothing happens either.

What am I missing?

Thanks

Armorial answered 17/11, 2011 at 3:18 Comment(5)
How are you writing .on()? because it should work, but i really hate the syntax of it, it's hard to tell if it's delegate or not.Mayor
@Matt: .live() and .delegate do the same basic thing (event delegation, by testing the event target when events bubble up). The difference is that .live() catches events all the way up at the document level, whereas .delegate() will catch them wherever you specify (i.e. closer, which is better). So, the .on() equivalent of .live() is $(document).on('event', '#selector .you > would've ~ used [with=live]', fn). Otherwise, .on() works like .bind() or .delegate(), depending on whether or not you provide a selector as the second argument.Unthinking
@DaveWard .on() works nothing like .live(), try it. As far as i know, it just attaches an event handler to an element when the DOM is loaded, so unlike .live() it will not attach a handler to loaded nodes after the DOM has already been loaded. If you add the 2nd selector, it will treat it as .delegate(), which again is nothing like live.Mayor
@Matt: Maybe the misunderstanding here is that .live() doesn't attach new handlers when elements are added to the DOM. When you write something like $('.targets').live('click', fn) what actually happens is jQuery begins monitoring click events that bubble up to the document object, checks to see if their eventTarget matches .targets, and executes your function if they do. It uses exactly the same approach that .delegate() does, but with less flexibility to catch the bubbling events closer to where they occur. Using $(document).on('click', '.targets', fn) does the same thing.Unthinking
@DaveWard oh ok, got you. Yea that makes perfect sense.Mayor
M
35

Heres the example they have, but with the delegate:

http://jsfiddle.net/HDtz3/

vs non-delegate: http://jsfiddle.net/HDtz3/1/

This is why i hate the new on syntax.

In yours simply do:

$('#MainDiv').on({
  mouseenter: function () { .... },
  mouseleave: function () { .... },
  blur: function () { ... }
}, '.MyTextBox');

and it should work

Mayor answered 17/11, 2011 at 3:30 Comment(6)
ok, very cool; looks the same but apparently it's running faster.Armorial
@Armorial yes it should look the same, reason it runs faster is because it targets one element instead of propagating through all the nodes to get to that one. They made this change with .delegate() and basically what I think they did was combine regular events with delegate, so you can make them "live" or not with .on()Mayor
I figure out that #MainDiv has to be non-dynamic element (not being loaded again through ajax).Wollongong
Got it. The $('nearest parent in which event may occur').on({...event actions...}, 'element on which the change will occur');Tswana
@Phelios I've added an answer that accounts for dynamic loading.Leopoldoleor
I hate the new syntax too. Given a large block inside the on(...) it's very confusing since you can't see what on is actually bound to. Worst jQuery syntax everIncursion
L
18

tl;dr: For direct swap-in replacement (accounts for dynamic loading), see the General Example below.


As other posters have noted, the accepted answer works, but $(#MainDiv') needs be a "non-dynamic element (not being loading again through ajax)". This is preferable performance-wise, as the event bubbling "distance" is limited. In the example, it only needs to bubble up to it's parent element to be handled.

The solution would be to bind to the "parent-most" element that is not going to be reloaded (via AJAX usually) - in the example, you'd need to bind to $('#MainDiv')'s parent.

However,

If you do want a direct swap-in replacement for live(), all you need to do is bind to the document element instead.

Generic examples

format 1:

//Replace:
$(selector).live(events, handler);           // Where `events` is a string

//With:
$(document)  .on(events, selector, handler); 

format 2:

//Replace:
$(selector).live(events);                    // Where `events` is 
                                             //   an object of `handler`s
//With:                                      //   (as in OP's example)
$(document)  .on(events, selector);

Note that with the on() examples,selector's container(s) can change and the binding will be automatically applied; the same functionality as live().

OP's example (format 2)

//Deprecated live() version:
$('.MyTextBox').live({
   mouseenter: function () { .... },
   mouseleave: function () { .... },
   blur: function () { ... }
});

//New on() version
$(document).on({
   mouseenter: function () { .... },
   mouseleave: function () { .... },
   blur: function () { ... }
},'.MyTextBox');
Leopoldoleor answered 15/3, 2013 at 16:52 Comment(1)
Don't you mean ".on" in your second version of OP's Example?Fraze
Y
1

Aaron, Matt, I think you've got the selector in the wrong order (for a live conversion), Have a look at the API documentation for on- http://api.jquery.com/on/#example-7

$("body").on("click", "p", function(){
  //stuff
});

When I tried your method (I came here looking for a solution for updating my core version), console errors popped up for everything (1.8, 1.9 and 2.0). The target element should be the second parameter not the last. Not sure why your answer has been accepted as it doesn't work. Hope this helps.

Yachting answered 13/5, 2013 at 16:38 Comment(5)
It's the same thing. See the fiddles.Cynthea
With all the mambo jumbo, this is the clearest answer and easiest drop-in replacement for .live(). I kinda liked .live(), shame it was removed.Paulpaula
Shadow Wizzrd, it's not the same, when I tried it in that format with the target element as the last parameter, it didn't work.Yachting
Our answers are correct. See my Format 1 example, which is what you cited in your answer. Matt's answer and my Format 2 example use a different "overload" of on that accepts an object as the first arg, the selector as the second argument, and no third arg. Why no third arg? Note that "format 2" combines the event and handler ("click" and function(){}) into the first arg ({click: function(){}}), so the third arg (handler) becomes unnecessary/redundant.Leopoldoleor
Either way, the target element is always the second argument (and because of the overload without a 3rd arg, could also happen to be the last arg).Leopoldoleor

© 2022 - 2024 — McMap. All rights reserved.