100

Is there a well-known mistake I could be making here?

I've got a script that's using .on() because an element is dynamically generated, and it isn't working. Just to test it out, I replaced the selector with the dynamic element's wrap, which is static, and it still didn't work! When I switched to plain old .click for the wrap it worked, though.
(This just won't work for the dynamic element obviously, the one that matters.)

This works:

$("#test-element").click(function() {
    alert("click");
});

This doesn't:

$(document).on("click","#test-element",function() {
    alert("click");
});

UPDATE:

I right-clicked and did "Inspect Element" in Chrome to just double-check something, and then after that the click event worked. I refreshed and it didn't work, inspected element, and then it worked. What does this mean?

Vikrant
  • 4,920
  • 17
  • 48
  • 72
Mr. Lavalamp
  • 1,860
  • 4
  • 17
  • 29

7 Answers7

179

You are using the correct syntax for binding to the document to listen for a click event for an element with id="test-element".

It's probably not working due to one of:

  • Not using recent version of jQuery
  • Not wrapping your code inside of DOM ready
  • or you are doing something which causes the event not to bubble up to the listener on the document.

To capture events on elements which are created AFTER declaring your event listeners - you should bind to a parent element, or element higher in the hierarchy.

For example:

$(document).ready(function() {
    // This WILL work because we are listening on the 'document', 
    // for a click on an element with an ID of #test-element
    $(document).on("click","#test-element",function() {
        alert("click bound to document listening for #test-element");
    });

    // This will NOT work because there is no '#test-element' ... yet
    $("#test-element").on("click",function() {
        alert("click bound directly to #test-element");
    });

    // Create the dynamic element '#test-element'
    $('body').append('<div id="test-element">Click mee</div>');
});

In this example, only the "bound to document" alert will fire.

JSFiddle with jQuery 1.9.1

itsmejodie
  • 4,148
  • 1
  • 18
  • 20
  • 1
    Unfortunately, I'm using a recent version of Jquery, my code is properly wrapped, it's inside $(document).ready, and the event being clicked is the lowest-level element in the document. This is baffling. – Mr. Lavalamp Jul 12 '13 at 00:01
  • I'd say "need to put the listener on the parent element" is not essential, although I too recommend it. Bubbling is what enables .on() to work. If we couldn't rely on bubbling to go past the immediate parent, it wouldn't be a great solution. – iGanja Jul 12 '13 at 00:01
  • @iGanja - good point and as you suggest, 'need' is not the right word since there are other less ideal ways to accomplish this. I revised my answer. – itsmejodie Jul 12 '13 at 00:07
  • if i am using "this" to reference element object then how can i attach it's event with document.. – Ashish Joshi Jan 11 '17 at 09:36
  • I have similar problem, I am already using document. Still its not working. My jQuery version is 1.7.2. Any suggestions – Saurabh Gupta Oct 18 '17 at 20:31
  • @itsmejodie.. super I was struck for 5 days.. its help full.. your answer help full. Thank you so much. – satish.kanikaram Dec 07 '17 at 09:50
  • I wrapped everything in an IIFE like that: (() => { // trigger })(); and forgot to write the "()"-brackets at the end. So my trigger was never registred – momo Dec 27 '17 at 14:48
  • I'm having a very similar issue with a dynamically created button not bring triggered on click. Instead the 'document' can be clicked to fire the alert. I don't understand why. – Jason Glisson May 25 '18 at 00:38
  • 1
    @JasonGlisson my guess would be that while you have a listener on the document, there is either an issue with the event not bubbling up (from the click on the button), or the difference between `event.target` and `event.currentTarget` somewhere in your code, but there are many things it could be including pointer events being disabled on the button – itsmejodie May 25 '18 at 00:43
  • @itsmejodie Yep. I just discovered that this was the correct assumption. It was a bubbling up issue. – Jason Glisson May 25 '18 at 00:54
  • For me, the problem was the jQuery 1.4.4. The **Uncaught TypeError: jQuery(...).on is not a function** went away after upgrading to 1.11.3. – CAK2 Jul 15 '19 at 23:37
14

Your code should work, but I'm aware that answer doesn't help you. You can see a working example here (jsfiddle).

Jquery:

$(document).on('click','#test-element',function(){
    alert("You clicked the element with and ID of 'test-element'");
});

As someone already pointed out, you are using an ID instead of a class. If you have more that one element on the page with an ID, then jquery will return only the first element with that ID. There won't be any errors because that's how it works. If this is the problem, then you'll notice that the click event works for the first test-element but not for any that follow.

If this does not accurately describe the symptoms of the problem, then perhaps your selector is wrong. Your update leads me to believe this is the case because of inspecting an element then clicking the page again and triggering the click. What could be causing this is if you put the event listener on the actual document instead of test-element. If so, when you click off the document and back on (like from the developer window back to the document) the event will trigger. If this is the case, you'll also notice the click event is triggered if you click between two different tabs (because they are two different documents and therefore you are clicking the document.

If neither of these are the answer, posting HTML will go a long way toward figuring it out.

smilebomb
  • 5,123
  • 8
  • 49
  • 81
7

An old post, but I love to share as I have the same case but I finally knew the problem :

Problem is : We make a function to work with specified an HTML element, but the HTML element related to this function is not yet created (because the element was dynamically generated). To make it works, we should make the function at the same time we create the element. Element first than make function related to it.

Simply word, a function will only works to the element that created before it (him). Any elements that created dynamically means after him.

But please inspect this sample that did not heed the above case :

<div class="btn-list" id="selected-country"></div>

Dynamically appended :

<button class="btn-map" data-country="'+country+'">'+ country+' </button>

This function is working good by clicking the button :

$(document).ready(function() {    
        $('#selected-country').on('click','.btn-map', function(){ 
        var datacountry = $(this).data('country'); console.log(datacountry);
    });
})

or you can use body like :

$('body').on('click','.btn-map', function(){ 
            var datacountry = $(this).data('country'); console.log(datacountry);
        });

compare to this that not working :

$(document).ready(function() {     
$('.btn-map').on("click", function() { 
        var datacountry = $(this).data('country'); alert(datacountry);
    });
});

hope it will help

Sulung Nugroho
  • 1,605
  • 19
  • 14
  • You can avoid using $(document).ready to wait for the element to be added to the DOM if you instead start with $(document).on("click"... $(document).on("click","#selected-country",function() { }); – Loren Oct 05 '20 at 17:42
  • The hint to use `$('body').on( 'click', '.class', .. )` made my day. Neither `$(document).on( 'click', '.class' )` nor `$( '.class' ).on( 'click', ..)` worked in my scenario, having static (loaded while page was served) and dynamic (loaded via ajax) elements. Thx! – matthaeus Oct 26 '22 at 08:28
4

This works:

<div id="start-element">Click Me</div>

$(document).on("click","#test-element",function() {
    alert("click");
});

$(document).on("click","#start-element",function() {
    $(this).attr("id", "test-element");
});

Here is the Fiddle

iGanja
  • 2,374
  • 2
  • 28
  • 32
  • 1
    That is not a dynamically generated element, as per the question. – itsmejodie Jul 11 '13 at 23:52
  • 1
    @itsmejodie - agreed, but it is dynamically bound to the event handler. changing the id is essentially no different than appending a DOM element. – iGanja Jul 11 '13 at 23:53
3

if this code does not work even under document ready, most probable you assigned a return false; somewhere in your js file to that button, if it is button try to change it to a ,span, anchor or div and test if it is working.

$(document).on("click","#test-element",function() {
        alert("click bound to document listening for #test-element");
});
Hakan
  • 240
  • 3
  • 4
1

Try this:

$("#test-element").on("click" ,function() {
    alert("click");
});

The document way of doing it is weird too. That would make sense to me if used for a class selector, but in the case of an id you probably just have useless DOM traversing there. In the case of the id selector, you get that element instantly.

Eduárd Moldován
  • 1,495
  • 3
  • 13
  • 29
  • 2
    How is this different from `$("#test-element").click(function() {` ? – Sushanth -- Jul 11 '13 at 23:43
  • Actually though, it works! What exactly is going on here? My assumption was always that (document).on worked for dynamically generated elements because it checked the ID of clicks on the whole document and wasn't reliant upon anything that existed on document load/ready. – Mr. Lavalamp Jul 11 '13 at 23:44
  • 3
    You have to use .on() to bind events to dynamically generated DOMs - anything that's bound with .click() will attempt to bind when the document is ready, and if the dom isn't present nothing will happen. – JTravakh Jul 11 '13 at 23:45
  • Wait. Nevermind, it didn't work, I was being dumb. It worked for the previously existing parent wrap but still not for dynamic content. – Mr. Lavalamp Jul 11 '13 at 23:46
  • 2
    But using `.on` without using a `selector` is the same as directly applying the click event on it – Sushanth -- Jul 11 '13 at 23:47
  • It isn't. My mistake on that. I wanted to point out that you should use this one instead of your second. That probably doesn't even get bound. – Eduárd Moldován Jul 11 '13 at 23:47
  • 2
    This isn't the correct answer for the question. This will bind directly to the element and therefore is not suitable when the element has been generated dynamically. – itsmejodie Jul 11 '13 at 23:49
  • I right-clicked and did "Inspect Element" in Chrome to just double-check something, and then after that the click event worked. I refreshed and it didn't work, inspected element, and then it worked. What does this mean? – Mr. Lavalamp Jul 11 '13 at 23:50
  • Guys, from the jquery docs: As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live(). here http://api.jquery.com/live/ --- .on has to work. – Eduárd Moldován Jul 11 '13 at 23:52
  • And it doesn't matter if you bind it directly to a id or class or with the above weird document selector. On has to work, always. – Eduárd Moldován Jul 11 '13 at 23:57
  • @EduárdMoldován - how is that relevant? we are talking about .on() – iGanja Jul 11 '13 at 23:58
  • @EduárdMoldován - you're totally wrong, there are two versions of on(), this is not the right one, the right one is in the OP's code. – adeneo Jul 12 '13 at 00:06
  • Guy, have you read the jQuery docs? Let me quote again, seams unclear for some: "For example, instead of $("body").on("click", "#commentForm .addNew", addComment) use $("#commentForm").on("click", ".addNew", addComment)." You can all find this here: http://api.jquery.com/on/#event-performance - and on is dynamic too. The problem is not this, probably something else. – Eduárd Moldován Jul 12 '13 at 00:13
  • 1
    I have actually read the docs, but the section on performance doesn't really have anything to do with delegated event handlers, and your code is not a delegated event handler. – adeneo Jul 12 '13 at 00:19
  • Mine isn't, obviously. $(document).on("", ... whatever) is. Also, I could not find the two different .on -s - could you please provide links to both? I am curious on the one I am not familiar with, as you say. Why are we fighting about this anyway? .on has to work if used properly, with proper selectors. – Eduárd Moldován Jul 12 '13 at 00:24
  • This goes against the whole point of the question, the element is dynamic. – doublejosh Jul 08 '15 at 02:41
0

$(document).on('click', '#test-element', () => { $('any class/id').hide(); });

*you can use whatever you want instead of hide.