106

So right now, I understand that in order to attach an event listener to a dynamically added element, you have to redefine the listener after adding the element.

Is there any way to bypass this, so you don't have to execute a whole extra block of code?

informatik01
  • 16,038
  • 10
  • 74
  • 104
Wiz
  • 4,595
  • 9
  • 34
  • 51

4 Answers4

206

Using .on() you can define your function once, and it will execute for any dynamically added elements.

for example

$('#staticDiv').on('click', 'yourSelector', function() {
  //do something
});
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
Jack
  • 10,943
  • 13
  • 50
  • 65
  • Is there a way to use .on() on events that are not in native jquery. i.e. I need to use it with a Jquery plugin. – Wiz Aug 22 '12 at 01:55
  • @Wiz: you can bind to any event – zerkms Aug 22 '12 at 01:56
  • @zerkms Well I'm trying to use it with Hovercard, and $('.class').on('hovercard', function(){}); is not working, when the usual syntax is $('.class').hovercard(function(){}); – Wiz Aug 22 '12 at 02:00
  • @Wiz - Delegated event handling (which is what you need for this solution) only works with events that propagate. This includes most mouse related events, but not all events. it looks like you're trying to use it with a `hovercard` event. That isn't really an event is it? – jfriend00 Aug 22 '12 at 02:03
  • @Wiz is `.class` also dynamically added? Also your missing the selector. `parentDiv` needs to exist when your binding the event, you may need to bind to the `document` if you don't have a static parent element to bind to. – Jack Aug 22 '12 at 02:05
  • @Jack I changed it to $(document).on('hovercard', '.class', function(){});, but right now, its not working for static or dynamic elements. – Wiz Aug 22 '12 at 02:09
  • @Wiz - I don't think you can use `.hovercard()` with `.on()`. `.on()` works with events, not with jQuery plugins calls. – jfriend00 Aug 22 '12 at 02:14
  • @jfriend00 then is there any way I can just define the event once and let it work for all dynamically added elements, or is the only way to add an event listener every time I add an element. – Wiz Aug 22 '12 at 02:16
  • @Wiz you might be able to hook in to the `mouseover event` of a parent element and over there initialize the plugin. – Jack Aug 22 '12 at 02:19
  • @Wiz, one would have to examine how the hovercard plugin source code works in order to answer that. Next time, please specify important details like this in your question. As it is your question asks about event listeners, but what you really want is hovercard installation so the answers to the question you wrote don't help you at all with your real problem. – jfriend00 Aug 22 '12 at 02:25
  • @jfriend00 yea I thought it would be like any other event. – Wiz Aug 22 '12 at 02:34
  • @Wiz - `.hovercard` isn't an event - it's a method call. `.on()` works with events. – jfriend00 Aug 22 '12 at 02:36
  • 1
    @Wiz Here's a very basic [jsfiddle](http://jsfiddle.net/aauMs/1/) to get you started, you might want to make sure that nothing adverse happens when you call the plugin multiple times on an element. ( note I started the fiddle off of one of demos since I didn't see a cdn for the hovercard plugin) – Jack Aug 22 '12 at 02:36
  • i'm using `.one("mouseenter"` and hitting the same hurdle can anyone help? @Wiz – pavitran Apr 08 '17 at 08:23
  • wont work. It still works on 1 element – AlwaysConfused Jun 19 '17 at 22:39
  • What if the ‘staticDiv’ itself is dynamic? Can you still delegate the event listener? – HPWD Jan 02 '19 at 05:35
  • @HPWD No, but you can always go further up the DOM and if need be delegate directly on the `body` (for example `$('body').on('click','.yourSelector', function () {...})` – Jack Jan 02 '19 at 14:26
  • I just realized you said `body` and not `document`. I've updated my code accordingly. I just wanted to make that distinction since the other answer below references the `$(document)`. I missed that on my initial review. – HPWD Jan 02 '19 at 16:03
  • 1
    @HPWD both will work, the document is above the body in the dom. There isn't really going to be much practical difference but in general you want to bind your handler to the closest element possible so it doesn't "bubble" up further then it needs to. I recommend you read up on [event bubbling](https://www.sitepoint.com/event-bubbling-javascript/) to get a better understanding. – Jack Jan 02 '19 at 20:26
  • @Jack Is this still relevant today ? It doesnt seem to be working for me ! – tejas Oct 09 '20 at 05:38
  • @tejas Yes, it still works today, are you sure that the "static div" exists on the DOM when you are running you code? – Jack Oct 12 '20 at 14:11
  • @Jack, Thank you for your response. I think there was something I couldnt understand and refactored the code a bit and it started working. – tejas Oct 13 '20 at 15:45
49
$(document).on('click', 'selector', handler);

Where click is an event name, and handler is an event handler, like reference to a function or anonymous function function() {}

PS: if you know the particular node you're adding dynamic elements to - you could specify it instead of document.

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 11
    Don't use `$(document)`. The event should be bound to the closest static parent. – Joseph Silber Aug 22 '12 at 01:48
  • 7
    @Joseph Silber: I've added PS for that. And "don't use" is too much categorical. There are valid cases for using it (don't even mention it is specified in jquery documentation: http://api.jquery.com/live/) – zerkms Aug 22 '12 at 01:49
6

You are dynamically generating those elements so any listener applied on page load wont be available. I have edited your fiddle with the correct solution. Basically jQuery holds the event for later binding by attaching it to the parent Element and propagating it downward to the correct dynamically created element.

$('#musics').on('change', '#want',function(e) {
    $(this).closest('.from-group').val(($('#want').is(':checked')) ? "yes" : "no");
    var ans=$(this).val();
    console.log(($('#want').is(':checked')));
});

http://jsfiddle.net/swoogie/1rkhn7ek/39/

Luc Kim-Hall
  • 178
  • 1
  • 4
1

When adding new element with jquery plugin calls, you can do like the following:

$('<div>...</div>').hoverCard(function(){...}).appendTo(...)
haotang
  • 5,520
  • 35
  • 46