<li> click function not working after ajax[Event delegation issue] [duplicate] - javascript

This question already has answers here:
Events triggered by dynamically generated element are not captured by event handler
(5 answers)
Closed 9 years ago.
In my webpage i am updating the contents of an unordered list $.get() every 5 seconds. The problem is the click function for the list items is not working. The list items are getting updated fine as they should but something is wrong with the click function
$(document).ready(function(){
$(".request").click(function(){
alert("hello");
//do some stuff
});
window.setInterval(function() {
$.get('/changeListItems/',function(data,status){
//alert(data[0]);
$('#collabRequests > li').remove();
for(user in data)
$('#collabRequests').append('<li class=\"request\">'+'user-'+data[user]+' wants to collaborate!'+'</li>');
});
},5000);
});
<!-- Html snippet -->
<div id="invitedUsers">
<h2> List of users you have invited for this page</h2>
<ul id="collabRequests">
</ul>
</div>

Delegate the event
Replace
$(".request").click(function(){
with
$(document).on("click", ".request", function(){
Still better.. Replace the document with a static ancestor that is present on the page at the time the event was bound.

Your selector, $(".request") is evaluated once. It does not periodically scan the DOM to find new elements with that class and attach click handlers to them. You are dynamically modifying the contents and not reattaching your handler.

The issue is that you're trying to attach an event handler directly on elements that do not exist in the DOM at the time that you're listening for their events.
As Sushanth suggested, the best way to handle events on dynamically injected DOM nodes is to simpy delegate them.
The other option is to bind the event handler at the time you add the new node to the DOM, but this can quickly get expensive if you're adding/removing many nodes. You'll also need to remember to unbind event handlers whenever an element is removed from the DOM tree or else your script may end up leaking memory.

Related

Clicking a <span> tag to run JQuery javascript function [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
I create a span using PHP like this.
if ($subnetkey == 1 ) { echo ("<span class='subnetkey'>S/N of: $subnetnum</span> ");}
It works, and shows the correct data on screen. Additionally if I look at it using 'Inspect Element' its properly formatted.
<span class="subnetkey">S/N of: 780</span>
I have this script at the top of the page. I've also tried it at the bottom.
<script>
$(document).ready(function(){
$(".subnetkey").click(function() {
alert("subnet click mode");
});
});
</script>
When I click the span, nothing happens. I get no errors, and of course I don't see the alert fire.
It seems like this is a timing issue between building the page dynamically and using the page. But in case thats not it, what can I do to make the function fire?
JQuery Event Methods like click(), dblclick(), mouseenter() etc. work only for elements already created when DOM is rendered. For dynamically created elements you use on() method with the below syntax (see previous post):
$(staticAncestors).on(eventName, dynamicChild, function() {});
Since it is a dynamically created element your code won't work. Try:
$(document).on('click', '.subnetkey', function() {
alert("subnet click mode");
});
jQuery is only aware of the elements in the page at the time it runs, so new elements added to the DOM are unrecognized by jQuery. To combat the problem use event delegation, bubbling events from newly added items up to a point in the DOM which was there when jQuery ran on page load. Many people use document as the place to catch the bubbled event, but it isn't necessary to go all the way up the DOM tree. Ideally you should delegate to the nearest parent existing at the time of page load.

Loaded html content with ajax wont detect other js functions [duplicate]

This question already has answers here:
JavaScript does not fire after appending [duplicate]
(3 answers)
Closed 7 years ago.
Guys i have blog post list loaded with ajax that list append html in one div. That ajax html result have some buttons witch need to execute some js events on click. Problem is bcs that loaded html result wont detect some events...
With ajax i get full post list like below post-list.php but when i try to click on button like or dislike in that ajax result event is not fired idk whay all that functions is in one file. I check to inspect with firebug he only detect listPosts() function.
See example:
In my index this result is loaded :
post-list.php file
<!-- List of post loaded from db (LOOP)
<h1>Post title</h1>
<p> Post content </p>
<button id="like">Like</button> <!-- jquery click event need to be fired but wont -->
<button id="dislike">Dislike</button> <!-- the some -->
Script example:
var Post = {
addPost: function() {
// Ajax req for insert new post
}
listPosts: function() {
// Ajax req for fetching posts
}
likePost: function() {
// example
$("#like").click(function() {
console.log("liked") // debug
$.ajax() // etc;
});
dislikePost: function(obj) {
// the some
});
init: functon() {
Post.addPost();
Post.listPosts();
Post.likePost();
Post.dislikePost();
}
}
Post.init();
This script load all post with ajax, add new post on some event, send like result in db and dislike. So in this post list result when i try to click like or dislike button nothing is happening.
Only work if i do this:
<button id="like" onclick="Post.likePost(this);">Like</button>
But i dont want to do this in this way. I dont understand that script detect listPosts() but wont detect other functions in that ajax response.
Event bubbling.
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers. This
element could be the container element of a view in a
Model-View-Controller design, for example, or document if the event
handler wants to monitor all bubbling events in the document. The
document element is available in the head of the document before
loading any other HTML, so it is safe to attach events there without
waiting for the document to be ready.
$('#container-div').on('click', '#like', function() {
console.log('Liked');
});
If you have a static container-div, it will have all events within it bubble up, i.e. it can see any events caused by dynamically created objects.
I would recommend to use class name instead of duplicating same ids again and again:
<button class="like">Like</button>
<button class="dislike">Dislike</button>
Now you can delegate the event to the static parent element:
$('staticParent').on('click', '.like', Post.likePost)
.on('click', '.dislike', Post.dislikePost);
where $('staticParent') would be the container element which holds the buttons and it was there before posts load. Although you can replace it with $(document) too, but lookup from document could make event execution a bit slow.
The solution to this problem would be to use "event delegation". This is a very powerful feature, and allows you to use event handlers without needing to explicitly attach them to an element or group of elements. This is an example:
$('#like').on('click',handleLike);
This would mean that anything matching the selector will have the callback fired. Also, I would recommend changing from using ids to something more generic, like CSS classes.

jQuery click function does not work properly on the 2nd run [duplicate]

This question already has answers here:
Click event doesn't work on dynamically generated elements [duplicate]
(20 answers)
Closed 7 years ago.
Here's a simplified version of my jQuery script that I cannot force to work properly.
http://jsfiddle.net/qk2nupq6/ (code's also below)
There's a "#press" div within a "#container". After pressing "#press", the content of "#container" is changed via .html() but the "#press" is still there so that is can be pressed again and the function can be run again.
For some reason, after pressing the button once, the function does not run again and I do not really have any clue why is that so.
HTML
<div id="container">
<div id="press">press </div>
</div>
JS
$(document).ready(function(){
$("#press").click(function(e){
console.log("x");
$("#container").html($("#container").html()+"<div>added</div>");
})
})
When you replace the innerHTML of the element the events bound to the elements are removed. So, when you replace the HTML even with the same content, previously bound events will not 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.
Use on to bind event
$('#container').on('click', '#press', function() {
Demo
$(document).ready(function() {
$("#container").on('click', "#press", function(e) {
$("#container").html($("#container").html() + "<div>added</div>");
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div id="container">
<div id="press">press</div>
</div>
You can use .append() like this:
$(document).ready(function(){
$("#press").on('click', function(e){
console.log("x");
$("#container").append("<div>added</div>");
})
})
Here is the FIDDLE.
Explanation:
You were replacing the html of the element so, any event bound to it
were removed.
Use Event Delegation:
Event delegation refers to the process of using event propagation
(bubbling) to handle events at a higher level in the DOM than the
element on which the event originated. It allows us to attach a single
event listener for elements that exist now or in the future. Inside
the Event Handling Function.
Or Append new data to existing element

.click not being registered on button [duplicate]

This question already has answers here:
jQuery click event not working after adding class
(7 answers)
Closed 7 years ago.
I have this button rendered after some text in an unordered list:
The button's HTML is like this:
<a
data-action="remove"
data-class-name="ECEC 301 Advanced Programming for Engineers Lab"
class="btn btn-danger remove-item btn-xs btn-font-12-px btn-raised margin-add-to-cart mdi-content-remove-circle-outline">
</a>
And this is the unordered list element it is within:
I am trying to write some jQuery that calls an action when the button is clicked, but no matter what I write, I just cannot register the click action, for example:
$('.btn.btn-danger.remove-item').on('click', function(){
console.log("you should see this");
});
$("[data-action]").click(function() {
console.log("yeah");
});
$('a[data-action="remove"]').click(function() {
console.log("yeah");
});
EDIT: The button is created dynamically AFTER page-load using jQuery (I call my JSON API to create the unordered list of classes)
Since button is generated dynamically you need to use event delegation
$(document).on('click','.btn.btn-danger.remove-item', function(){
console.log("you should see this");
});
Event delegation refers to the process of using event propagation (bubbling) to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach a single event listener for elements that exist now or in the future.
Taken from : http://learn.jquery.com/events/event-delegation/
The issue is that the element doesn't exist when the click handler is being added.
Basically, you are saying "hey jquery, find this element and do XYZ when it is clicked". jQuery looks for it, doesn't find anything (since the element has not been created yet), and since it is chill it doesn't say anything to you about it (it would be super annoying if it errored out all of the time).
The way around this is by using event delegation. What that means is that you attach the event to an element that will be there, and then jQuery filters every event sent to that parent element and checks to see if the event that triggered it happened to an element that matches the selector.
It may sound complicated, but it is straight forward. All you need to do is update
$(".btn.btn-danger.remove-item").on("click...
to this
$(document).on("click", ".btn.btn-danger.remove-item"...

Two Ajax dynamically created elements can't recognize each other

Dear Stack Overflow community,
I have been trying to develop a table creator that creates two tables dynamically when a button is clicked. This has worked... Well it hasn't at least for now.
Right now I am generating a <p> element with class heading and a <div> element with class content. When p is clicked, content is slideToogled.
I have tried using on() with jQuery or attaching any function to the element but it doesn't seem to work. Also .hide() doesn't work on content which is extremely annoying. Can anyone give me some advice as to how to approach this please?
On seems to work for content I hard written with HTML, but it doesn't on AJAX generated code appended to the div.
Here are the related snippets of code:
Ajax:
function submition() {
$.ajax({
type: 'GET',
url: 'phpQueries.php?q=getQueryBuilder&schools=' + mySchools.toString()+ '&depts=' + myDeps.toString() + '&lvls=' + myLevs.toString() + '&srcs='+mySrc.toString() + '&codes='+myCodes.toString(),
success: function (data) {
$("#dump_here").append(data);
}
});
jquery:
$(".heading").on("click", function() {
alert("Hello World");
$(this).next(".content").slideToggle(500);
});
PHP:
echo '<p class="heading">See/Hide Comments</p> ';
echo '<div class="content">I am I am I am.... Superman!</div>';
Kind Regards,
Gempio
This because (if I understand correctly) you create a <p> tag with the class heading after you assign the click event handler.
What you want to do is delegate your events to a container that contains your <p> tag. So, let's assume this is your structure:
<div id="dump_here"></div>
You then do this in your JavaScript:
$("#dump_here").on("click", ".heading", function () {
....
This way you assign an event handler to the parent container which already exists, and the event will bubble up once you click on your paragraph. Now you can dynamically add new elements to your HTML within that container and your event handlers will still work.
Why is that? Because you can't assign event handlers to elements that don't exist.
When you do this:
$(".something").click(...)
You don't tell Javascript to do something whenever you click any element with the something class on the page, you assign an event handler to every single already-existing something on the page. If you create a new element, even if it is the same class, you still need to assign an event handler to it.
A quote from the jQuery documentation:
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on()
Also David Walsh wrote a nice article explaining Event Delegation.
Hope this helps.
Change this:
$(".heading").on("click", function() {
alert("Hello World");
$(this).next(".content").slideToggle(500);
});
to:
$(document).on("click", ".heading", function() {
alert("Hello World");
$(this).next(".content").slideToggle(500);
});
Alternatively you can put the definition of $(".heading").on("click", ...) into your AJAX success callback, but if you have multiple .heading elements you'll run into multiple event bindings for elements that were there before the AJAX runs, say if it runs twice and appends 2 tables. The reason your method didn't work is the element has to exist before the event is bound. The 1st option I proposed works because the document is where the event is bound, and the last option works because it's in the callback of the AJAX that creates the element, so the element exists at the time it was bound.
So let's say, that this is your HTML:
<div id="dump_here">
<!-- contents here are dynamic - these don't exist when the page first loads -->
<p class="heading">See/Hide Comments</p>
<div class="content">I am I am I am.... Superman!</div>
<!-- end of dynamic content -->
</div>
Now on doc ready you attach your handler:
$(function() {
// $(".heading").click(//...this won't work, heading doesn't exist on load
$("#dump_here").on("click",".heading",function() {
// this will work - the handler is attached to an element that exists on load
// and will respond to event that bubble up from elements with the class 'heading'
});
submition(); // async function that populates your dynamic parts.
});
Be sure to read the docs on .on()
The important part to understand is this:
$(".heading")
This returns a collection of jQuery objects that represent DOM elements that have the class of heading. If there are no matching elements in the DOM when you execute that line, you will have an empty collection. But jQuery won't complain about this and will still let you chain to that empty collection:
$(".heading").on("click", function() { //...
What this says is attach an event handler to all the matching dom elements in my collection that will execute this function when the click event is triggered. But if your collection is empty, it won't do anything.

Categories

Resources