151

I want to bind an onclick event to an element I insert dynamically with jQuery

But It never runs the binded function. I'd be happy if you can point out why this example is not working and how I can get it to run properly:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="da" lang="da">
 <head>
 <title>test of click binding</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
 <script type="text/javascript">
 jQuery(function(){
 close_link = $('<a class="" href="#">Click here to see an alert</a>');
 close_link.bind("click", function(){
 alert('hello from binded function call');
 //do stuff here...
 });
 
 $('.add_to_this').append(close_link);
 });
 </script>
 </head>
 <body>
 <h1 >Test of click binding</h1>
 <p>problem: to bind a click event to an element I append via JQuery.</p>
 <div class="add_to_this">
 <p>The link is created, then added here below:</p>
 </div>
 <div class="add_to_this">
 <p>Another is added here below:</p>
 </div>
 </body>
 </html>

EDIT: I edited the example to contain two elements the method is inserted to. In that case, the alert() call is never executed. (thanks to @Daff for pointing that out in a comment)

Saurabh Agrawal
7,7553 gold badges30 silver badges52 bronze badges
asked Oct 6, 2009 at 13:40
3
  • 1
    Your example page runs fine when I tested it in FF 3.5 Commented Oct 6, 2009 at 13:49
  • @Daff Unfortunately you're right! Then I have apparently extracted the part of my code that actually works. Thanks for pointing that out! Commented Oct 6, 2009 at 13:54
  • @Daff, I edited the example so it containts two places to insert the method. Then it really stopped working :) Commented Oct 6, 2009 at 14:01

9 Answers 9

340

All of these methods are deprecated. You should use the on method to solve your problem.

If you want to target a dynamically added element you'll have to use

$(document).on('click', selector-to-your-element , function() {
 //code here ....
});

this replace the deprecated .live() method.

giannis christofakis
8,3424 gold badges56 silver badges67 bronze badges
answered Oct 1, 2012 at 13:03

5 Comments

*selector-to-your-element* should be '.some-class' or '#some-id'
My issue was that I was doing something like $('.row').on('click', function(){...}); instead of $(document).on('click','.row',function(){...});
Remember $(document) can be any element that doesn't change on your page. This prevents excessive event bubbling, speeding up your JS. Eg. $(document) -> $('.example-container')
How do I know which element if it is a list?
73

The first problem is that when you call append on a jQuery set with more than one element, a clone of the element to append is created for each and thus the attached event observer is lost.

An alternative way to do it would be to create the link for each element:

function handler() { alert('hello'); }
$('.add_to_this').append(function() {
 return $('<a>Click here</a>').click(handler);
})

Another potential problem might be that the event observer is attached before the element has been added to the DOM. I'm not sure if this has anything to say, but I think the behavior might be considered undetermined. A more solid approach would probably be:

function handler() { alert('hello'); }
$('.add_to_this').each(function() {
 var link = $('<a>Click here</a>');
 $(this).append(link);
 link.click(handler);
});
answered Oct 7, 2009 at 8:33

4 Comments

there's a problem when you have to bind clicks on elements appended with other functions. That's why I suggest to use aM1Ne answer.
Indeed, when you are targeting known markup structures created by some other code. But here he was inserting the elements himself, and there is no clear selector for them (it's just an anchor, which there might be many of), so he would have to add additional markup to be able to target the element. In that case it's just as easy to attach the handler to the element directly, instead of capturing all clicks and test for selector match.
I understand your answer, didn't mean it was wrong. Surely, being able to dynamically inject some html (like a ul li of pictures loaded with ajax of infinite scroll stuff) and already having buttons bound to some action (like a lightbox) it's much more comfortable.
This answer is also very helpful for cases where an older version of jQuery is available by default (eg. Drupal 7). on() was introduced in jQuery 1.7.
50

How about the Live method?

$('.add_to_this a').live('click', function() {
 alert('hello from binded function call');
});

Still, what you did about looks like it should work. There's another post that looks pretty similar.

answered Oct 6, 2009 at 13:53

6 Comments

you are right that it actually worked. my mistake. So I have edited the question.
Yeah, this sort of problem is exactly what live events are intended to solve.
The problem is not related to live events though in this case a live event would solve it. The answer provided by Daff also solves the problem, and does it without adding the new concept of live events to the equation
live() is now deprecated in favor of on() link
live() was deprecated and replaced by on() in jQuery 1.9
|
25

A little late to the party but I thought I would try to clear up some common misconceptions in jQuery event handlers. As of jQuery 1.7, .on() should be used instead of the deprecated .live(), to delegate event handlers to elements that are dynamically created at any point after the event handler is assigned.

That said, it is not a simple of switching live for on because the syntax is slightly different:

New method (example 1):

$(document).on('click', '#someting', function(){
});

Deprecated method (example 2):

$('#something').live(function(){
});

As shown above, there is a difference. The twist is .on() can actually be called similar to .live(), by passing the selector to the jQuery function itself:

Example 3:

$('#something').on('click', function(){
});

However, without using $(document) as in example 1, example 3 will not work for dynamically created elements. The example 3 is absolutely fine if you don't need the dynamic delegation.

Should $(document).on() be used for everything?

It will work but if you don't need the dynamic delegation, it would be more appropriate to use example 3 because example 1 requires slightly more work from the browser. There won't be any real impact on performance but it makes sense to use the most appropriate method for your use.

Should .on() be used instead of .click() if no dynamic delegation is needed?

Not necessarily. The following is just a shortcut for example 3:

$('#something').click(function(){
});

The above is perfectly valid and so it's really a matter of personal preference as to which method is used when no dynamic delegation is required.

References:

answered Jun 13, 2013 at 11:48

Comments

3

It is possible and sometimes necessary to create the click event along with the element. This is for example when selector based binding is not an option. The key part is to avoid the problem that Tobias was talking about by using .replaceWith() on a single element. Note that this is just a proof of concept.

<script>
 // This simulates the object to handle
 var staticObj = [
 { ID: '1', Name: 'Foo' },
 { ID: '2', Name: 'Foo' },
 { ID: '3', Name: 'Foo' }
 ];
 staticObj[1].children = [
 { ID: 'a', Name: 'Bar' },
 { ID: 'b', Name: 'Bar' },
 { ID: 'c', Name: 'Bar' }
 ];
 staticObj[1].children[1].children = [
 { ID: 'x', Name: 'Baz' },
 { ID: 'y', Name: 'Baz' }
 ];
 // This is the object-to-html-element function handler with recursion
 var handleItem = function( item ) {
 var ul, li = $("<li>" + item.ID + " " + item.Name + "</li>");
 if(typeof item.children !== 'undefined') {
 ul = $("<ul />");
 for (var i = 0; i < item.children.length; i++) {
 ul.append(handleItem(item.children[i]));
 }
 li.append(ul);
 }
 // This click handler actually does work
 li.click(function(e) {
 alert(item.Name);
 e.stopPropagation();
 });
 return li;
 };
 // Wait for the dom instead of an ajax call or whatever
 $(function() {
 var ul = $("<ul />");
 for (var i = 0; i < staticObj.length; i++) {
 ul.append(handleItem(staticObj[i]));
 }
 // Here; this works.
 $('#something').replaceWith(ul);
 });
</script>
<div id="something">Magical ponies ♥</div>
answered Jul 9, 2013 at 8:13

Comments

2

Consider this:

jQuery(function(){
 var close_link = $('<a class="" href="#">Click here to see an alert</a>');
 $('.add_to_this').append(close_link);
 $('.add_to_this').children().each(function()
 {
 $(this).click(function() {
 alert('hello from binded function call');
 //do stuff here...
 });
 });
});

It will work because you attach it to every specific element. This is why you need - after adding your link to the DOM - to find a way to explicitly select your added element as a JQuery element in the DOM and bind the click event to it.

The best way will probably be - as suggested - to bind it to a specific class via the live method.

answered Oct 6, 2009 at 13:43

3 Comments

Thanks for answer, Daff. It can't be true that I can only add event listeners to elements in DOM. However, i will for now change my code to do that. (should be no problem as I just add special css class for the links added).
Yeah you are right it's not the DOM (it actually works with a single one), sorry. But I found out, too, that binding to dynamically created elements seems to be pretty annoying, as long as they are not selectable by a distinct jQuery selector.
"hello from BOUND function call." Sorry, there are too many of those on this post (whole page; question and answers) and I just want to help, you know, clear that up.
1
 function load_tpl(selected=""){
 $("#load_tpl").empty();
 for(x in ds_tpl){
 $("#load_tpl").append('<li><a id="'+ds_tpl[x]+'" href="#" >'+ds_tpl[x]+'</a></li>');
 }
 $.each($("#load_tpl a"),function(){
 $(this).on("click",function(e){
 alert(e.target.id);
 });
 });
 }
answered Jun 6, 2017 at 0:19

Comments

0

I believe the good way it to do:

$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );
answered Oct 6, 2009 at 13:47

1 Comment

I can't use #id to add to element, because I want to do this for many elements. See the updated code example :)
-1
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
<script>
 $(document).ready(function(){
 $(document).on('click', '.close', function(){
 var rowid='row'+this.id;
 var sl = '#tblData tr[id='+rowid+']';
 console.log(sl);
 $(sl).remove();
 });
 $("#addrow").click(function(){
 var row='';
 for(var i=0;i<10;i++){
 row=i;
 row='<tr id=row'+i+'>'
 + '<td>'+i+'</td>'
 + '<td>ID'+i+'</td>'
 + '<td>NAME'+i+'</td>'
 + '<td><input class=close type=button id='+i+' value=X></td>'
 +'</tr>';
 console.log(row);
 $('#tblData tr:last').after(row);
 }
 });
 });
</script>
</head>
 <body>
 <br/><input type="button" id="addrow" value="Create Table"/>
 <table id="tblData" border="1" width="40%">
 <thead>
 <tr>
 <th>Sr</th>
 <th>ID</th>
 <th>Name</th>
 <th>Delete</th>
 </tr>
 </thead>
 </table>
 </body>
 </html>
f.khantsis
3,5906 gold badges52 silver badges73 bronze badges
answered May 14, 2017 at 4:43

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.