Two Ajax dynamically created elements can't recognize each other - javascript

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.

Related

How can I either target an Appended element using Jquery or Javascript, or how can I add that appened element to the DOM?

I've looked all over the internet with everyone giving the same answer
$(document).on('click', '#targetID', function() {
// do stuff
});
instead of
$('#targetID').click(function() {
// do stuff
});
This is nice and it works fine, if you have a click event. But within that on click function, the part where it says do stuff, how can I now target an appended element? For instance say I append 2 divs back to back.
<div id="mainDiv"></div>
<script>
socket.on('event', function (data) {
$('#mainDiv').append ('<div class="1st" id="'+data.id+'">one</div>
<div class="2nd" id="'+data.id+'">second</div>');
});
$(document).on('click', '.1st', function() {
//and right here i would like to`enter something like
$('.2nd').css('background-color','yellow');
}
</scirpt>
This however seems not to work because to my knowledge, this element hasn't been added to the DOM. So what should I do? Should i use angular.js for this?
PS I've also tried adding the entire appended content into a variable first before appending that variable. and then using variable.find to find the element within to no avail. The variable only has context within that function, but is null in the on click function. Thanks in advance for any information that broadens my understanding of this.
The delegation of 'on' is correct. Once the div element exists in the dom, clicking should work. My only concern is you have named your classname beginning with a number. Maybe name it with an alpha character followed by a number.
The difference between the 2 is the concept of event binding vs event delegation.
$('#targetID').click(function() { is event binding which works on elements as long as they exist in the markup when the page or document loads.
$(document).on('click', '#targetID', function() { is event delegation which means the event would listen to the document for the click event on the element with ID targetID if it exists in the DOM when the page loads or if it is dynamically added.
So In your case, its event delegation since you are dynamically adding the elements. But in order to make it work, you need to register the listener on the document ready event for the document to listen to the event on the element #targetID
<script>
$(document).ready(function() // Add this
{
socket.on('event', function (data) {
$('#mainDiv').append ('<div class="1st" id="'+data.id+'">one</div><div class="2nd" id="'+data.id+'">second</div>');
});
$(document).on('click', '.1st', function() {
//and right here i would like to`enter something like
$('.2nd').css('background-color','yellow');
});
});
</script>
Here's an example : https://jsfiddle.net/nobcp0L7/1/

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.

How can jquery capture an <input> file tag that was itself rendered using jquery after a user clicks? [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 9 years ago.
How do you hook into javascript / popup functionality that is invoked after a user clicks?
We have javascript code that gets invoked by a user click. This javascript code renders a popup dialog that contains an choose file tag. This choose file tag is literally appended by doing something like:
output.append('<input type="file" ......'>
So the problem with this is if the user doesn't first click this tag never gets rendered in the response.
We are currently using a jQuery $() function to execute our code that looks for tags as soon as the web page loads, however our $() function does not get called when the user clicks the link rendering the popup.
Is there another hook we can use in jQuery besides $() that gets invoked when a popup gets rendered?
If I understand correctly, you want to attach an event handler at page load time to an input that will not exist until the user clicks a link. One solution is to use event delegation. You can look for "delegated events" in the documentation for the .on() function.
Basically, you call .on() on an element that already exists in the DOM that is an ancestor of the element that will be added later. You supply a selector as the second parameter that identifies the element you want the handler to execute for.
You could use:
$(document).ready(function() {
$(document.body).on('click', 'input:file', function() {
...
});
});
But it is more efficient to use a closer ancestor than the <body> element if you can, and you might have a better selector for identifying the file input element than the one I show above (since it will match all file input elements).
Either create proper elements with event handlers :
var file_input = $('<input />', {
type : 'file',
on : {
change : function() {
// do stuff
}
}
});
output.append(file_input);
or use a delegated event handler
output.on('change', '.file_input', function() {
// do stuff
});
output.append('<input type="file" class="file_input" ......'>
Of course it is possible. You have to define your function for the later rendered element after it is rendered.
HTML:
<div id="holder">
<button id='first'>first</button>
</div>
JQuery:
$('#first').click(function () {
alert('first click');
$('#holder').append("<input id='second' type='file' name='pic' accept='image/*'>");
$('#second').click(function () {
alert('second click');
});
});
Here is a demo: JSFIDDLE

jQuery append - html wrote doesn't trigger other events

Maybe i should be more specific.
I've a javascript function, called from here:
<input id="Text1" type="text" onkeyup="Trova('Text1');" />
The function, search into an array and, with jquery, draws new rows into a table (ID #tabdest):
$("#tabdest").append('<tr><td class="preview" nome="' + nomi[i] + '" >' + nomi[i] + '</td></tr>');
Everythings is ok until now. Into my .js file I've this function that shoud be executed:
$(document).ready(function () {
$(".preview").mousemove(function (event) {
...
This function works correctly if I write a table manually but doesn't if jQuery write it.
I'm sorry for my terrible English, hope to find help
Thanks anyway
Use .on()
As elements are added dynamically you can not bind events directly to them .So you have to use Event Delegation.
$("#tabdest").on('mousemove','.preview',function(event){ ... });
Syntax
$( elements ).on( events, selector, data, handler );
Although the other answers have correctly identified that you should be using event delegation (through the use of jQuery's on function) I wanted to explain a bit about how your code is currently working.
$(document).ready(function () {
$(".preview").mousemove(function (event) {
...
Translated into words this is: When the document is ready search for all elements with class "preview" and add an event handler to these elements for the mouse move event. jQuery doesn't do magic.
$('.preview')...
is basically doing
document.getElementsByClassName('preview')
It's not doing any kind of mapping or binding to the DOM. This means when you add a new element with the class "preview" the code that added the event handlers would need to run again to pick this new element up.
Using:
$("#tabdest").on('mousemove', '.preview', function(e) { });
Binds the event handler to the "tabdest" element (which doesn't change) and when a user clicks on a child of this element (one of your newly created elements) the event bubbles up the DOM and runs this function.
Since the preview tabel cell is added dynamically, you need to use event delegation to register the event handler:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('#tabdest').on('mousemove', '.preview', function(event) {
alert('testlink');
//....
});
This will attach your event to any table cell with class preview within the #tabdest table element, reducing the scope of having to check the whole document element tree and increasing efficiency.

How to use same jquery fuunction on a multiple buttons that are created in a loop?

Im creating the same button in a loop as long as there is a certain condition, and I want to run the same jquery event handler for those buttons.
The problem is that the event handler only works for the first button generated.
My button is generated like this:
<?php while($row_c= mysqli_fetch_array($result_comments))
{ ?>
<button name="comment" id="comment" class="button_comment" value="Post">Post</button>
<?php } ?>
and the jquery im using is this:
$('.button_comment').click(function()
{
//some staff thats done here
});
What should do, so that the event handler works for all buttons that are generated?
Thank you
Your jQuery should work. Note that your buttons form invalid HTML/DOM: The id on an element must be unique. But since you're also using a class (which doesn't have to be unique), and that's what you're using in your jQuery selector, that works: Live Example | Source
Perhaps when you were trying it and it wasn't working, you were using $("#comment").click(...), which would not work, because of the id issue.
Check in firebug:
var buttoncomments = $('.button_comment');
console.log(buttoncomments);
Bind the control in question to a variable so you're certain that it's that one you're working with.
$('.button_comment').click(function()
{
var that = $(this);
"What should do, so that the event handler works for all buttons that are generated?"
A Fiddle would be a good way to show us the context of your problem ;)
Your code is valid because it will attach a handler to every element having 'button_comment' as a css class
Did you put this code inside a dom ready function ?
$(function(){
/* code here */
});
You can use event delegation
This mean you have to attach the event listener to the first common ancestor of those buttons. This is a good choice when many elements have to trigger the same routine an even more if some of them may be added to the DOM in the futur via AJAX (This keep the page from having to many event handlers attached to it)
Delegation syntax
// Event delegation
$( "#Ancestor").on("click", '.button_comment', function() {
alert( $( this ).val() );
});
Take the ID off from your php code. Remember ID's should be unique elements. Also, change your jquery from:
('.button_comment').click(function()
{
//some staff thats done here
});
to
('.button_comment').on('click', function()
{
//some staff thats done here
});
The on event will perform what you tell it to do at the time you tell it to do, so it does it pretty much at runtime. If you use your previous code, the element must exist at page load time for it to work.

Categories

Resources