Attaching click event to a JQuery object not yet added to the DOM

166,592

Solution 1

Use this. You can replace body with any parent element that exists on dom ready

$('body').on('click', '#my-button', function () {
     console.log("yeahhhh!!! but this doesn't work for me :(");
});

Look here http://api.jquery.com/on/ for more info on how to use on() as it replaces live() as of 1.7+.

Below lists which version you should be using

$(selector).live(events, data, handler); // jQuery 1.3+

$(document).delegate(selector, events, data, handler); // jQuery 1.4.3+

$(document).on(events, selector, data, handler); // jQuery 1.7+

Solution 2

I am really surprised that no one has posted this yet

$(document).on('click','#my-butt', function(){
   console.log('document is always there');
}) 

If you are unsure about what elements are going to be on that page at that time just attach it to document.

Note: this is sub-optimal from performance perspective - to get maximum speed one should try to attach to the nearest parent of element that is going to be inserted.

Solution 3

Try this.... Replace body with parent selector

$('body').on('click', '#my-button', function () {
    console.log("yeahhhh!!! but this doesn't work for me :(");
});

Solution 4

Try:

$('body').on({
    hover: function() {
        console.log("yeahhhh!!! but this doesn't work for me :(");
    },
    click: function() {
        console.log("yeahhhh!!! but this doesn't work for me :(");
    }
},'#my-button');

jsfiddle example.

When using .on() and binding to a dynamic element, you need to refer to an element that already exists on the page (like body in the example). If you can use a more specific element that would improve performance.

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(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.

Src: http://api.jquery.com/on/

Solution 5

You have to append it. Create the element with:

var $div = $("<div>my div</div>");
$div.click(function(){alert("clicked")})
return $div;

Then if you append it will work.

Take a look at your example here and a simple version here.

Share:
166,592

Related videos on Youtube

danielrvt
Author by

danielrvt

Computer Engineer graduated from Universidad Simon Bolivar, currently living in Caracas, Venezuela. GIS, Mobile and Web app developer... Web is my favorite. Always thinking about user experience and passionate about Python and JavaScript (There is something sexy about dynamic languages...). I also love using GIT and developing Augmented Reality applications with ARToolkit. My account on GitHub is this: https://github.com/danielrvt. See you on SO!!!

Updated on July 08, 2022

Comments

  • danielrvt
    danielrvt almost 2 years

    I've been having a lot of trouble attaching the click event to a JQuery object before adding it to the DOM.

    Basically I have this button that my function returns, then I append it to the DOM. What I want is to return the button with its own click handler. I don't want to select it from the DOM to attach the handler.

    My code is this:

    createMyButton = function(data) {
    
      var button = $('<div id="my-button"></div>')
        .css({
           'display' : 'inline',
           'padding' : '0px 2px 2px 0px',
           'cursor' : 'pointer'
         }).append($('<a>').attr({
           //'href' : Share.serializeJson(data),
           'target' : '_blank',
           'rel' : 'nofollow'
         }).append($('<image src="css/images/Facebook-icon.png">').css({
           "padding-top" : "0px",
           "margin-top" : "0px",
           "margin-bottom" : "0px"
         })));
    
         button.click(function () {
            console.log("asdfasdf");
         });
    
         return button;     
    }
    

    The button that is return is unable to catch the click event. However, if I do this (after the button is added to the DOM):

    $('#my-button').click(function () {
        console.log("yeahhhh!!! but this doesn't work for me :(");
    });
    

    It works... but not for me, not what I want.

    It seems to be related to the fact that the object is not yet a part of the DOM.

    Oh! By the way, I'm working with OpenLayers, and the DOM object that I'm appending the button to is an OpenLayers.FramedCloud (Which is not yet a part of the DOM but will be once a couple of events are triggered.)

    • frenchie
      frenchie almost 12 years
      Look into jquery's .on() It's for attaching event handlers at runtime
    • ayyp
      ayyp almost 12 years
      Maybe try binding click on creation of the element?
    • danielrvt
      danielrvt almost 12 years
      @AndrewPeacock what do you mean by binding click on creation?
    • ayyp
      ayyp almost 12 years
      @danielrvt At the end of the create, do something like $("#my-button").bind("click"); I believe you'd need to unbind it at some point though.
    • Reed G. Law
      Reed G. Law over 11 years
      I'm having a similar problem with leaflet. It seems to be related to the map disabling click propagation. Could that be the case with your issue?
  • frenchie
    frenchie almost 12 years
    .live() is deprecated and replacced with .on()
  • j08691
    j08691 almost 12 years
    This won't work if my-button is loaded dynamically.
  • jbabey
    jbabey almost 12 years
    click is shorthand for bind('click' ...)
  • jbabey
    jbabey almost 12 years
    @j08691 yes it will, that's the point of live, delegate, and on.
  • j08691
    j08691 almost 12 years
    @jbabey- Read the documentation on on(). If his element is created dynamically, you have to bind to an existing page element. "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()."
  • j08691
    j08691 almost 12 years
    This won't work if my-button is loaded dynamically.
  • danielrvt
    danielrvt almost 12 years
    @j08691 is right, if the element is created dynamically it won't work.
  • danielrvt
    danielrvt almost 12 years
    I tried this just now and it doesnt work, it appears that the "on" method must be used with elements that are already in the DOM. "The .on() method attaches event handlers to the currently selected set of elements in the jQuery object"
  • wirey00
    wirey00 almost 12 years
    It should work. "on" replaces "live" which attaches events to current/future selectors which means any element with the id="my-button" should have that click event attached to it
  • danielrvt
    danielrvt almost 12 years
    This is right, however it will only work with the hover event and not with the click event...
  • wirey00
    wirey00 almost 12 years
    Can you make a fiddle for us to see exactly what the problem is?
  • j08691
    j08691 almost 12 years
    I'm not sure I understand what you mean. .on() definitely works with the click event.
  • danielrvt
    danielrvt almost 12 years
    I'am so sorry, it works in deed, but with 'hover', not with 'click'... I'm trying to figure out why...
  • danielrvt
    danielrvt almost 12 years
    I know... its so rare... when I use: $('body').on('click hover', '#my-button', function () {console.log('hello');}) it works, but only on hover, also if I remove the "click" from above it will work with hover, but if I leave "click" it doesn't do anything... :(
  • wirey00
    wirey00 almost 12 years
    Here's a fiddle I made to test out 'on' click. jsfiddle.net/X8KcU/1
  • j08691
    j08691 almost 12 years
    I don't believe you can do that with on(). Maybe with bind you had that option, but with on() you have to do something like $('body').on({ hover: function() { }, click: function() { } }
  • danielrvt
    danielrvt almost 12 years
    Thanks @wirey, I see what you did there, but it still wont work for me... I'm starting to think that it has to do with OpenLayers and the FramedCloud...
  • j08691
    j08691 almost 12 years
    See my updated answer and example.
  • wirey00
    wirey00 almost 12 years
    I'm a little confused about your variable "button". What exactly are you storing in it? Looks like you are selecting ('<div id="my-button"></div>') element? Is that what you are trying to get?
  • danielrvt
    danielrvt almost 12 years
    Actually what I want is to create a popup with OpenLayers and put a button inside to display information about my map... As the popup is created dynamically, I have no other choice but to create the button on the go.
  • wirey00
    wirey00 almost 12 years
    Something like this fiddle? jsfiddle.net/X8KcU/3
  • Roberto Alarcon
    Roberto Alarcon over 11 years
    "You can replace BODY with any parent element that EXISTS ON DOM ready" that's the key, thanks man!
  • Roberto Alarcon
    Roberto Alarcon over 11 years
    BTW @danielrvt this worked for you? because it's not marked as an answer.
  • sage88
    sage88 over 10 years
    I just used this and it works. Not sure if it worked for the OP, but it's definitely correct.
  • Ajedi32
    Ajedi32 over 10 years
    Unfortunately this solution isn't ideal because it requires that I add an ID to the element I'm listening for events from. I'd rather the createMyButton function return an element that already has an event listener attached to it. Is that possible in JQuery?
  • wirey00
    wirey00 over 10 years
    @Ajedi32 not necessarily - You just need the right css selector to target your element. Can you explain more on what exactly you're trying to do?
  • Ajedi32
    Ajedi32 over 10 years
    @ᾠῗᵲᄐᶌ I've already solved my problem by waiting until after the element is added to the DOM to attach the event, but the problem was related to this: github.com/Ajedi32/html_checkers/blob/… I want to bind an event to the HTMLCheckerPiece immediately after it is instantiated, even if it hasn't yet been added to the DOM. I don't want to bind the event to all checker pieces, since the event should only be triggered for an individual checker piece when it is clicked.
  • mr5
    mr5 about 10 years
    Yay! Works for me, thanks :D
  • andrewb
    andrewb almost 9 years
    I did something like this, and it worked fine.
  • andrewb
    andrewb almost 9 years
    I said it worked fine, so no issue. This is my preferred solution, as it means the handlers are dynamic like the content. Basically treating the content as a partial view with its own controller, which I really like.
  • whoan
    whoan almost 9 years
    I see you answered first with a simple typo, so my +1 is for you for the intention. Great solution. Thanks!
  • James Wierzba
    James Wierzba over 7 years
    Can this be used to set a property of an element that has not yet been added? (checking a checkbox in my case)
  • wirey00
    wirey00 over 7 years
    @JamesWierzba not to set a property. This is to bind an event handler to listen for dynamic elements. If you want to set a property of an element you can after it has been added to the DOM. How exactly is the checkbox getting added?
  • James Wierzba
    James Wierzba over 7 years
    Ok I thought so. The checkbox is added dynamically after an ajax call to the server, which responds with the info required to create it. I've done what you suggested and manipulated it after the input was added to the DOM.
  • Johnny Bigoode
    Johnny Bigoode over 7 years
    On the performance perspective, how would you measure that?
  • Matas Vaitkevicius
    Matas Vaitkevicius over 7 years
    @JohnnyBigoode only way to make it worse would be to attach it to window :) , it will have to bubble up all the way through the html (child->parent->...document). I would still do it though... there are far worse things...
  • Matas Vaitkevicius
    Matas Vaitkevicius over 7 years
    @JohnnyBigoode and accepted answer (on average) will be 2 levels up which is pretty much negligible...
  • Johnny Bigoode
    Johnny Bigoode over 7 years
    I'm just wondering, how one would go around measuring javascript performance... is there any recommended way?
  • Matas Vaitkevicius
    Matas Vaitkevicius over 7 years
    @JohnnyBigoode well you would put up two identical pages and then attach couple of thousand of events to elements at the bottom of the page then you would add timer and check how do times compare... If I were you - I wouldn't waste the time on this though....
  • Johnny Bigoode
    Johnny Bigoode over 7 years
    Nah, I was just really curious how this kind of performance check is made.
  • Fabien Haddadi
    Fabien Haddadi over 6 years
    Using .on() is normally the way to go indeed, but it doesn't always work like it should. I'm currently with FF 47.0 and jQuery 1.12, and the event doesn't fire off on lately loaded DOM contents. The initially loaded DOM contents triggers it though. In this case, you may have to create a specific event handler that listens to the object once loaded live in a callback for example. Attention, it is then easy to multiply even listeners and create a massive duplicate set of calls...
  • Si8
    Si8 over 6 years
    What about .each() adding to .on()
  • raj m
    raj m almost 5 years
    @MatasVaitkevicius my butt ? lol