jQuery how to bind onclick event to dynamically added HTML element [duplicate] - javascript

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
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)

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.

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);
});

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.

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:
jQuery docs for .on()
jQuery docs for .click()
jQuery docs for .live()

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.

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>

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);
});
});
}

I believe the good way it to do:
$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );

<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>

Related

Is there a way to apply jQuery to dynamically created elements? (not event listeners)

I have dynamically created an element with the following class:
<span class="text">Hello</span>
and jQuery:
function changeText() {
var oldText = $(this).text();
$(this).text(oldText + " There");
}
$(function() {
$(".text").each(function(){
changeText.apply(this);
})
})
Obviously, this is a simplified version of what is actually happening but the basics are there. Is it possible to apply this rule to dynamically created elements even though we are not using event listeners?
The problem here is that there is no specific location for these ".text" elements. The only place we know these will show up is in the body. I we use a mutationObserver on the body... wouldn't that be taxing performance?
Do this instead:
function changeText() {
var oldText = $(this).text();
$(this).text(oldText + ' There');
}
$(function(){
$('.text').each(function(i, e){
changeText.call(e);
});
});
Like this
$dynamicElement.find(".text").each(function(){
changeText.apply(this);
})

Call a function outside AJAX when I click button inside the ajax response [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
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)
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.
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);
});
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.
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:
jQuery docs for .on()
jQuery docs for .click()
jQuery docs for .live()
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.
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>
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);
});
});
}
I believe the good way it to do:
$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );
<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>

Why isn't this.parent() defined as a function?

JSFiddle
I'm creating a new button element with
$('<button>Remove Entry</button>', { 'type': 'button', 'class': 'delete_button' });
However the neither the type or class attributes seem to be defined, and the console prints an error saying this.parent() is not a function (though I'm positive I enabled jquery)
I'm afraid I've done something simple and stupid, but I can't seem to find anything wrong.
The reason that the attributes are not set on the element, is that you are mixing different uses of the jQuery method.
To use the method in a way that it uses an object for attributes, the first parameter should be a single tag, not a HTML snippet:
$('<button>', { 'type': 'button', 'class': 'delete_button' }).text('Remove Entry');
The reason that this doesn't have a parent method is that it refers to an element, not a jQuery object. You would use $(this) to make a jQuery object from the element reference.
Also, this referers to the new entry button, not the remove entry button, as you are calling the method when you are binding the event. You should call the method when the event happens:
delete_button.click(function() {
remove_entry($(this).parent())
});
Demo: http://jsfiddle.net/Guffa/9TcpB/1/
var entries = 0;
function new_entry() {
entries++
new_entry_div = $('<div>', { 'class': 'entry' }).appendTo('form');
new_entry_div.html('<p><input type="text"></p>')
// delete button
delete_button = $('<button>', { 'type': 'button', 'class': 'delete_button' }).text('Remove Entry');
delete_button.appendTo(new_entry_div);
delete_button.click(function(){
remove_entry($(this).parent());
});
}
function remove_entry(entry) {
entry.remove();
}
$("#newButton").click(function () {
new_entry();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="input">
<form>
</form>
<button id="newButton">New Entry</button>
</div>
You're basically doing this
$("#newButton").click(function() {
new_entry;
});
function new_entry() {
this.parent();
}
but inside the callback for the event handler, this is native JS DOM element, not a jQuery object, so it has no jQuery methods, you have to wrap it first, as in
$("#newButton").click(new_entry);
function new_entry() {
$(this).parent();
}
this contains a DOM element. If you want to use jQuery methods, you have to convert it to a jQuery object with $(this).
jsFiddle Demo
Retain the current context using the call method:
$("#newButton").click(function () {
new_entry.call($(this));//now this in new_entry refers to `$(this)`
})

How to add onclick event in dynamicly add html code via JavaScript?

I try to add some list element in loop via JS. Every element <li>contains <a> tag, now I want to add onClick event in every adding <a> tag. I try to do it so:
liCode = '<li>Text using variable foo: ' + foo + '</li>';
$('#list').append(function() {
return $(liCode).on('click', clickEventOccurs(foo));
});
In clickEventOccurs I just output to console foo. It works in strange way: this event performed just on init when every tag is adding to list, but after click on <a> doesn`t perform anything. How to make it works in proper way - on click performed code in clickEventOccurs?
Firstly, you are assigning not a callback function, but a result of function evaluation. In right way it should be like this:
$('#list').append(function() {
return $(liCode).click(function() {
clickEventOccurs(foo);
});
});
Also, as you are using jQuery you might use benefits of events delegation and use .on method this way:
$('#list').on('click', 'li', function() {
return clickEventOccurs(foo);
});
on() is good for handling events, even to elements which will be created dynamically.
$('body').on('click', '#list li', function(){
clickEventOccurs(foo);
});
http://jsfiddle.net/lnplnp/uGJnc/
HTML :
<ol id="list">
<li>Text using variable foo: foovalue</li>
</ol>
JAVASCRIPT/JQUERY :
function appending(foo) {
liCode = '<li>Text using variable foo: ' + foo + '</li>';
$('#list').append($(liCode));
}
$('#list').on('click', 'li', function() {
return clickEventOccurs($("a", this).text());
});
function clickEventOccurs(v){
console.log(v.split(":")[1].trim());
}
appending("foo1");
appending("foo2");
appending("foo3");
To pass a variable to that function you'll have to make a second anonymous one, otherwise your clickEventOccurs function will be called at assignment, not as a callback.
$('#list').append(function() {
return $(liCode).click(function() {
clickEventOccurs(foo)
});
});

add event for sub children in jquery

Just a little help for me here with jquery.
This is my problem. I have a list
<ul>
<li>
<p>Name</p>
Delete
</li>
</ul>
the 'Delete' event click was initiation in jquery when load page. So the issue now, i'd like to add an element <li></li> which contain children like above. I used jquery to create the tag 'li' contain children, then 'prepend' to the 'ul'.
The problem is, i can not call 'delete' event on new item. Somebody help me please
try this DEMO
var contentToAdd = ' <li> <p>Name</p> Delete </li>';
$('ul').prepend(contentToAdd);
$('ul').on('click','a', function(){
alert('click');
});
The problem is that you're most probably using .click or bind('click') to attach the click event handler to the element. This is fine if all of the elements exist at the time when you attach the event, if however you create new elements that match that same selector, they will not get that event attached.
You need to use the delegate() or .on() method to attach the event to all elements that are current on the page or are appended to the page after they're set up.
An example of a delegate that catches the click event and appends a new element that you can click and see that the same event is attached to each new part of the DOM that matches the selector.
$('#list').delegate('a','click',function() {
alert('Click event fired - Adding a new element to test!');
$('ul').append('<li><p>Name</p>Delete</li>');
return false;
});
Or using the newer .on method:
$('#list').on('click','a',function() {
alert('Click event fired - Adding a new element to test!');
$('ul').append('<li><p>Name</p>Delete</li>');
return false;
});
$('#list') is what my example uses to denote the <ul>, but you could just as easily use $('ul') if you don't want to put an id or class on the list.
Example Fiddle
take a look at this jQuery example:
(one of the last examples on http://api.jquery.com/on/)
<!DOCTYPE html>
<html>
<head>
<style>
p { background:yellow; font-weight:bold; cursor:pointer;
padding:5px; }
p.over { background: #ccc; }
span { color:red; }
</style>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
<p>Click me!</p>
<span></span>
<script>
var count = 0;
$("body").on("click", "p", function(){
$(this).after("<p>Another paragraph! "+(++count)+"</p>");
});
</script>
</body>
</html>
which means in your case you need something like:
$("ul").on("click", "a", function(e){
// delete logic goes here
})
Add the click listener on the UL rather than the a's themselves. This way it will automatically detect clicks to newly added items as well.
$(document).ready(function() {
$("ul").on("click li > a", function() {
$(this).closest("li").remove();
});
});
You can use the .on() method to do so,
The .on() method attaches event handlers to the currently selected set
of elements in the jQuery object
$(document).on("click", "ul li a"), function(){
//your code here
});
Test Link
You can try this,
$("ul").on("click", "a", function(e){
e.preventDefault();
$(this).closest('li').remove();
});
Okay, given that ".on" doesn't meet your requirements, perhaps something like:
$element = $('<li><p>Name</p>Delete</li>');
$element.find("a").click(function(){
//call your delete function
})
$("ul").prepend($element);
Why dont you use jquery templating.
You can define a text/template and iterate over it to get your desired result.
an example:
**THIS IS YOUR SCRIPT**
<script id="movieTemplate" type="text/x-jquery-tmpl">
<li><b>${Name}</b> was released in ${ReleaseYear}.</li>
</script>
**THIS IS THE JQUERY TEMPLATE**
<script type="text/javascript">
var movies = [
{ Name: "The Red Violin", ReleaseYear: "1998" },
{ Name: "Eyes Wide Shut", ReleaseYear: "1999" },
{ Name: "The Inheritance", ReleaseYear: "1976" }
];
// Render the template with the movies data and insert
// the rendered HTML under the "movieList" element
$( "#movieTemplate" ).tmpl( movies )
.appendTo( "#movieList" );
</script>
**THIS IS YOUR HTML**
<ul id="movieList"></ul>
More examples :
http://blog.reybango.com/2010/07/09/not-using-jquery-javascript-templates-youre-really-missing-out/

Categories

Resources