I don't know why this is not working.
When a li element is clicked I call a PHP file to get some results back and print them in my page. So far so good.
$("li").click(function(){
var item = $(this).html();
$.getJSON('fSearch.php',{sTerm: item}, function(data){
var results='';
$.each(data, function(i, item) {
results += "<li id='t'>"+item.Description+"</li>";
});
$('#ResultsHolder').html("<ul>"+results+"</ul>");
});
});
The first time I click to a li element all works fine, I get results. Now these results is another set of li's and I want them to behave the same, but when I click on the generated li's the function is not executed..
Why is this happening? Why jQuery does not recognize the dynamically inserted li elements?
Thanks in advance!
When you use a event shortcut (such as click, or hover) it will only work for events which are available to the DOM on page load. As you are appending elements dynamically you need to delegate the event listener to an element which is always available in your page.
In the example below, I've used #ResultsHolder.
$("#ResultsHolder").on("click", "li", function(){
var item = $(this).html();
$.getJSON('fSearch.php',{sTerm: item}, function(data){
var results='';
$.each(data, function(i, item) {
results += "<li id='t'>"+item.Description+"</li>";
});
$('#ResultsHolder').html("<ul>"+results+"</ul>");
});
});
That should work for jQuery 1.7+. For an older version of jQuery, use delegate()...
$("#ResultsHolder").delegate("li", "click", function(){ ...
Also, all the appended li elements have the id of 't'. This will end up with invalid code as ids should be unique. Use a class instead if you want to have a group identifier.
.click() is not a live handler, is only binds the event to elements that exist in the DOM at the time of execution. If you want the events to be live, you'll need to look into another handler, such as .on()
When you call ("li").click(), you are binding events to the existing li elements. When you create new li elements, you need to bind them to the event so the click will work.
So, change your loop to something more like this...
$.each(data, function(i, item) {
var li = $('li').text(item.Description);
$(li).click(function(e) { loadChildren(this); });
$("#ResultsHolder").append(li);
});
The 'li' elements that are added to the page don't have the function bound to their click event handler. You need to use the jQuery live() function to do this.
http://api.jquery.com/live/
Basically rather than .click(function(){}) you need to do .live("click",function(){})
Because the binding the .click functionality to all li's happened before this new one was created. JQuery has the .on() function, which could solve your issue.
$("li").on("click", function(event){
// do functionality
});
Use .delegate() : $(document).delegate("li","click",function(){...})
Or, the newer version, .on() $('li').on("click",function(){...})
If your li's are in some fixed div, you can make it faster by replacing document in the first snippet with the selector of that div; and make the second one $(SELECTOR).on("click","li",function(){...})
Related
This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 8 years ago.
Suppose I have some jQuery code that attaches an event handler to all elements with class .myclass.
For example:
$(function(){
$(".myclass").click( function() {
// do something
});
});
And my HTML might be as follows:
<a class="myclass" href="#">test1</a>
<a class="myclass" href="#">test2</a>
<a class="myclass" href="#">test3</a>
That works with no problem.
However, consider if the .myclass elements were written to the page at some future time.
For example:
<a id="anchor1" href="#">create link dynamically</a>
<script type="text/javascript">
$(function(){
$("#anchor1").click( function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});
});
</script>
In this case, the test4 link is created when a user clicks on a#anchor1.
The test4 link does not have the click() handler associated with it, even though it has class="myclass".
Basically, I would like to write the click() handler once and have it apply to both content present at page load, and content brought in later via AJAX / DHTML. Any idea how I can fix this?
I am adding a new answer to reflect changes in later jQuery releases. The .live() method is deprecated as of jQuery 1.7.
From http://api.jquery.com/live/
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().
For jQuery 1.7+ you can attach an event handler to a parent element using .on(), and pass the a selector combined with 'myclass' as an argument.
See http://api.jquery.com/on/
So instead of...
$(".myclass").click( function() {
// do something
});
You can write...
$('body').on('click', 'a.myclass', function() {
// do something
});
This will work for all a tags with 'myclass' in the body, whether already present or dynamically added later.
The body tag is used here as the example had no closer static surrounding tag, but any parent tag that exists when the .on method call occurs will work. For instance a ul tag for a list which will have dynamic elements added would look like this:
$('ul').on('click', 'li', function() {
alert( $(this).text() );
});
As long as the ul tag exists this will work (no li elements need exist yet).
Sometimes doing this (the top-voted answer) is not always enough:
$('body').on('click', 'a.myclass', function() {
// do something
});
This can be an issue because of the order event handlers are fired. If you find yourself doing this, but it is causing issues because of the order in which it is handled.. You can always wrap that into a function, that when called "refreshes" the listener.
For example:
function RefreshSomeEventListener() {
// Remove handler from existing elements
$("#wrapper .specific-selector").off();
// Re-add event handler for all matching elements
$("#wrapper .specific-selector").on("click", function() {
// Handle event.
}
}
Because it is a function, whenever I set up my listener this way, I typically call it on document ready:
$(document).ready(function() {
// Other ready commands / code
// Call our function to setup initial listening
RefreshSomeEventListener();
});
Then, whenever you add some dynamically added element, call that method again:
function SomeMethodThatAddsElement() {
// Some code / AJAX / whatever.. Adding element dynamically
// Refresh our listener, so the new element is taken into account
RefreshSomeEventListener();
}
Hopefully this helps!
Regards,
After jQuery 1.7 the preferred methods are .on() and .off()
Sean's answer shows an example.
Now Deprecated:
Use the jQuery functions .live() and .die(). Available in
jQuery 1.3.x
From the docs:
To display each paragraph's text in an
alert box whenever it is clicked:
$("p").live("click", function(){
alert( $(this).text() );
});
Also, the livequery plugin does this and has support for more events.
If you're adding a pile of anchors to the DOM, look into event delegation instead.
Here's a simple example:
$('#somecontainer').click(function(e) {
var $target = $(e.target);
if ($target.hasClass("myclass")) {
// do something
}
});
You can bind a single click event to a page for all elements, no matter if they are already on that page or if they will arrive at some future time, like that:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('.myclass')) {
e.preventDefault(); // if you want to cancel the event flow
// do something
} else if (target.is('.myotherclass')) {
e.preventDefault();
// do something else
}
});
Been using it for a while. Works like a charm.
In jQuery 1.7 and later, it is recommended to use .on() in place of bind or any other event delegation method, but .bind() still works.
Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events.
link text
$(function(){
$(".myclass").live("click", function() {
// do something
});
});
If your on jQuery 1.3+ then use .live()
Binds a handler to an event (like
click) for all current - and future -
matched element. Can also bind custom
events.
You want to use the live() function. See the docs.
For example:
$("#anchor1").live("click", function() {
$("#anchor1").append('<a class="myclass" href="#">test4</a>');
});
This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 7 years ago.
I've got a few functions in JQuery that stop working after I perform an Ajax request (to a PHP file) to add elements to the DOM.
This is the ajax function:
function paginacion(pagina){
$.ajax({
method: "GET",
url: "paginacion.php",
data: {pag: pagina}
})
.done(function(msg) {
$(".bt_container").remove();
$(".contenido").append(msg);
});
}
Here I call it:
$(".button").on("click", function(){
var pag = parseInt($(this).attr("data-pag"));
pag++;
paginacion(pag);
});
When I click the button, it works correctly the first time. But the elements I retrieve, should work with another function, and they don't, while the previous elements do work without any problem. Also, the old button gets removed and another one gets added at the end of the file, being retrieved by the same function as above. That button doesn't work either.
I'm sure that I'm having some problem with JQuery, making it to not work with these new DOM element's I'm retrieving. What can I do to make it work?
Use event delegation:
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
$(document).on('click', '.button', function () {
var pag = parseInt($(this).data("pag"));
// ^^^^
pag++;
paginacion(pag);
});
Also, use data() to get data attribute value.
http://api.jquery.com/data/
Refer: http://learn.jquery.com/events/event-delegation/
It is loaded dynamically! Use .on for Event Delegation.
$("body").on('click', '.button', function () {
var pag = parseInt($(this).attr("data-pag"));
pag++;
paginacion(pag);
});
You need to use .on() for bindig events for dynamically generated elements
$(document).on('click', '.button', function () {
var pag = parseInt($(this).attr("data-pag"));
pag++;
paginacion(pag);
});
You are looking for Event delegation. You dynamically added and replace the dom elements use event delegation.
$(".contenido").on("click", ".button", function(){
//------^ Immediate parent or document
// Your code
});
I'm trying to add a link to delete a row from a mysql database using jquery and ajax. The data is currently displayed in a table. For some reason, the Click event isn't triggering.
Here's my AJAX call:
<script>
$(document).ready(function() {
/* load table with page load*/
$("#sort tbody").load("inc/index_table.php");
/* row deletion */
$(".deletelink").click(function(){
var id = $(this).attr("id");
$.ajax({
beforeSend: function (request) {
var answer = confirm("Are you SURE you want to delete this?/nThis action is NOT reversible.")
if (answer){ return(true); }
else { return(false); }
},
type: "POST",
url: location.href,
data: "delete="+id,
error: function() {
console.log("Theres an error with AJAX deletion");
},
success: function(){ //a.td.tr.remove just that row rather than the whole table
$this.parent().parent().remove();
console.log("Deleted.");
}
});
});
});
</script>
And the relevant HTML:
this is part of a while loop that prints a table from my database:
<td><a class="deletelink" id="'.$row["id"].'"><img src="images/delete.png" alt="Delete"></a></td>';
My code specifies <a class="deletelink"> but it's not registering with $(".deletelink").click(function(){ });
Does anyone see what could be wrong here or have an alternate method to suggest?
Looks like you are loading the elements dynamically. You can only bind to elements which currently exist in the DOM. To bind to elements which you are about to add, you must attach the event to a static element, the closer it is to the dynamic content, the better.
Try using on() with a delegate.
$("#sort tbody").load("inc/index_table.php");
/* row deletion */
$("#sort tbody").on("click", ".deletelink", function(){
//...rest of code the same
});
on() was added in jQuery 1.7. If you are using a previous version, but higher than 1.4.2 you can use delegate() instead.
$("#sort tbody").load("inc/index_table.php");
$("#sort tbody").delegate(".deletelink", "click", function(){
//...rest of code the same
});
If #sort or tbody of $("#sort tbody") is also dynamic then $("document").on("click", "#sort tbody .deletelink", function(){...}) would work as well, though anything closer than document is better off course.
Edit
I'm just looking at your code again, the delegate binding should work, however, using load()'s success callback should work with your existing code too.
The callback is executed ones load has successfully completed. I'm not 100% certain but I'm assuming that when success is called that the elements already have been loaded into the DOM and as such the normal bindings should work.
If that doesn't work the dynamic bindings mentioned above should.
$("#sort tbody").load("inc/index_table.php", function(){
/* row deletion */
$(".deletelink").click(function(){
// .. your code as before.
});
});
to make sure the table is fully loaded, try to declare the click function, in the callback of .load() like,
$("#sort tbody").load("inc/index_table.php", function() {
/* row deletion */
$(".deletelink").click(function(){ ....
});
});
Try using .on() to bind the events to the elements
$(".deletelink").on('click',function(e){
e.preventDefault();
Also make sure to add preventDefault to stop the default functioning of the link
The problem is that your delete link appears after the table loads. So when page was loaded and DOM tree was built, it wasn't there. So you can't attach a click to it.
You can try live(). This can be used as
$(".deletelink").live('click',function(){
// ajax call handling code here
});
This function attaches event after the element has been introduced in the DOM. However, this function is a bit greedy as it keeps on scanning entire DOM tree on any DOM change. So use with caution
I have a button that does not work in jquery. A button is passed from php to Jquery using json object. I have removed all other code just the button to test to try and solve this.
I create the same link and place it on my page in php. when the link is clicked a alert appears and works.
On the same page I have an additional button which is the same button, but this button has been returned from PHP via json to Jquery and
appended to the div. This link/button does not work? why is this? both appear the same!
Hope someone can advise as to what is happening here
Thanks
button returned from PHP
//Jquery basic test button for functionality (works if link button is already on HTML page)
$("[href='#test']").click(function() {
alert("has been clicked");
});
//JQuery extract of my code
var content;
$.each(data, function(i, item) {
content += item;
});
$(content).appendTo('#theframe');
},'json');
have also tried
$.each(data, function(i, item) {
content += item;
});
$('#theframe').html(content);
},'json');
//php returned
$json[] = 'View Post';
echo json_encode($json);
//php button on page
View Post
Thanks
SOLVED with help from all posts, thank you! #Anthony's example added the frame
$('#theframe').on('click', '[href="#test"]', function(e) {
alert('has been clicked');
});
You will need to use the jQuery on() or delegate() functions to add the click event to new page elements that are added dynamically (after the page is loaded).
If you are using jQuery 1.7 and greater you should use on(): http://api.jquery.com/on/
If you are using an older version of jQuery use delegate: http://api.jquery.com/delegate/
The .click() function only adds the event handler to elements that exist when the code is run, so won't affect any elements that are added dynamically later on. The easiest solution to get around this is to set up event delegation, using either the .on() (jQuery 1.7+) or .delegate() (prior to 1.7) functions. The .on() example would look like this:
$('body').on('click', '[href="#test"]', function(e) {
alert('has been clicked');
});
the reason it does not work is that your document ready function only fires once. This means that after your second button loads via ajax, there is no event handler attached to it.
Try using "on" or "live":
$("body").on("click", a[href="#target"], function(event){
alert("has been clicked");
});
http://api.jquery.com/on/ <- Docs for "on"
http://api.jquery.com/ <- Your new favorite website!
Hope this helps!
I have dynamically generated a list of wine types from the database using AJAx and PHP
here is the function
function wineTypeHandler(data){
var Type = data.Type;
var countType = data.countType;
for(var i = 0; i < countType; i++){
$("#selectType").append(
$("<input />").attr({
type: 'checkbox',
name: 'Type',
class: 'wineTypeCheck',
value: Type[i]
}), Type[i] + "<br />"
);
}
}
As you can see I have "appended" the results to some div with id selectType, this whole thing works fine, my only problem is when I want to update another list based on what has been checked from this list, it doesnt respond to anything!. When i try this one and many other ways
$(document).ready(function(){
$(':checkbox').click(function(){
alert('started');
// other code
return true;
});
});
It doesnt alert anything!! Can anybody help me with this problem.
thank you in advance.
.click() attaches itself to elements that exist when the DOM is created. Your elements are being dynamically generated, so .click() doesn't actually get applied to them.
You should use .live() to target dynamically generated elements, as it attaches itself to any element that is created after the DOM is initially loaded. I also suggest using the change event instead of a click:
$(':checkbox').live('change', function(){
// No need to return true;
});
This is because you are assigning the click function once your page has loaded but before your checkboxes have been dynamically created.
Depending on what version of jQuery you are using you can use the on() (for jQuery version 1.7 or above), delegate() (for older versions of jquery) or live() (simple but inefficient) functions to register an event to dynamically created elements.
Just try this
$(':checkbox').live('change', function(){
});
You need to bind the click event after the element has been added to the DOM. This is a popular problem for JavaScript development. I'd recommend creating a function that sets the bind event, and calling it after your append call (as well as on jQuery(document).ready()).
Edit: I see a lot of recommendations for jQuery.live() It's important to note that the live() method of jQuery is deprecated and should not be used.
The event is bound only to the existing elements. You need to use live
$(':checkbox').live("click", function(){
alert('started');
});
EDIT:
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().
jQuery 1.4.3+ use delegate
$(#selectType).delegate(':checkbox', "click", function(){
alert('started');
});
jQuery 1.7+ use on
$(#selectType).on("click", ':checkbox', function(){
alert('started');
});