Multiple handlers attached to the same HTML element - javascript

I have a simple code. Everytime I click the "Start" button, 3 new buttons with unique IDs and values are created and appended to my div.
For each new button, if I click on it, it alerts the value inside the button. My problem is that if I click the "Start" button 4 times, so there are 12 new buttons created (it's OK), but whenever I click on any newly-created button, it alerts several times (not 1 time as I expect).
I guess the problem is that everytime I click button "Start", a new handler is attached to the button. How to avoid this problem. I have googled for jQuery off(), but it didnt help much. Any help is appreciated very much.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script type="text/javascript">
var count =1;
$( document ).ready(function() {
$('#start').on('click', function(e) {
var i;
for (i=0;i< 3;i++)
{
$('<button id = "Button' + count + '" value = "' + count + '">Button' + count + '</button>').appendTo('#mydiv');
count++;
}
for(i=1;i<= count;i++)
{
$(document).on("click", '#Button' + i , function(){
alert ( $(this).attr('value') );
});
}
});
});
</script>
</head>
<body>
<h1>Test dynamically created button</h1>
<div id = "mydiv">
<button id ="start">START</button>
</div>
</body>
</html>

Your guess is correct. You added handlers several times. This is fix.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script type="text/javascript">
$( document ).ready(function() {
var count = 1; //no need to make it global
$('#start').on('click', function(e) {
var i;
for (i=0;i< 3;i++)
{
$('<button id = "Button' + count + '" value = "' + count + '">Button' + count + '</button>')
.click(function(){//add handler when button created... and never more
alert (this.value);//or $(this).val()
})
.appendTo('#mydiv');
count++;
}
/* here you add handlers more and more times
for(i=1;i<= count;i++)
{
$(document).on("click", '#Button' + i , function(){
alert ( $(this).attr('value') );
});
}
*/
});
});
</script>
</head>
<body>
<h1>Test dynamically created button</h1>
<div id = "mydiv">
<button id ="start">START</button>
</div>
</body>
</html>

If your buttons stay in the DOM (like it seems at the moment), why don't you add the EventListener directly on the new added buttons like this:
$('#start').on('click', function(e) {
var i;
for (i=0;i< 3;i++) {
var myNewButton = $('<button id = "Button' + count + '" value = "' + count + '">Button' + count + '</button>');
myNewButton.appendTo('#mydiv');
myNewButton.on("click", function() {
alert ( $(this).attr('value') );
});
count++;
}
});
Otherwise, as you already guessed in your question, you adding additional Listeners to your existing buttons since you loop through all of them.

At every click on start you create event handlers also for the buttons that are already on the page, meaning they get several handlers attached to them, the more you click on the start button.
Simply add the following handler on document ready (not on click), and it will capture any future button's click if it has an id like Button*:
$(document).on('click', '[id^=Button]', function () {
alert ($(this).attr('value') );
});
Remove the creation of such click handler from the start button's handler.
So the code becomes:
$(document).ready(function() {
var count = 0;
$(document).on('click', '[id^=Button]', function () {
alert ($(this).attr('value') );
});
$('#start').on('click', function(e) {
var i;
for (i=0;i<3;i++) {
$('<button id = "Button' + count + '" value = "' + count + '">Button' + count + '</button>').appendTo('#mydiv');
count++;
}
});
});
So this way, you only have two handlers: one for the start button, and one for all other Button* buttons. No need to dynamically add new handlers.

Related

jquery click function not working even after using $(document).ready(function() {}); and even after using $(function) block

I am trying to extract the id=obj1 from the string html_doc and trying to attach an onclick function to it
document.addEventListener("DOMContentLoaded",
function (event) {
$ajaxUtils.sendGetRequest("data/GOG123.json",
function (res) {
var residue=res.residues;
var html_doc = "<div>" + "<Button id = obj1>" + residue[0].index + "</Button> " + "</div>";
console.log(html_doc);
var html_doc2;
html_doc2= $("html_doc").find("obj1");
$(document).ready(function(){
html_doc2.click(function () {
alert("Hello!");
});
});
var div1=$("#infoDiv");
div1.append(html_doc);
}
);
});
It is not working (i.e not showing an alert message) neither it is throwing any error.
Can someone please help me with the same?
I referred to Why is this jQuery click function not working? but it did not work out for me.
you can also use .on() click event.
$(document).on("click", "#obj1", function(){
alert("clicked");
});
Try to put ajax in either function or inside document ready.without extracting id you can do same thing if you know id.
var html_doc = "<div>" + "<Button id = obj1> Click" + "</Button> " + "</div>";//instead of click put ur code
var div1 = $("#infoDiv");
div1.append(html_doc);
$(document).ready(function() {
$("#obj1").click(function() {
alert("Hello!");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id=infoDiv>This is div info</div>

Jquery .on Listener don't add click listener to new elements

I'm having this problem (here I summarize) in which the Jquery .on method adds the listener to the first button that is created when loading the page but when the other is created by clicking the previous one the new button does not contain any listener although I indicated that it should look inside body for the element with the id that has the value of the variable count. According to the .on method you can add listeners to objects created later on the page.
Here is the HTML:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<script src="script.js"></script>
</body>
</head>
and here is script.js
var count = 1;
$("body").html("<button id=\"" + count +"\">1</button>");
$("body #" + count).on("click", function(){
count++;
$("body").html($("body").html() + "<button id=\"" + count +"\">" + count +"</button>");
});
var count = 1;
$("body").html("<button id=\"" + count +"\">1</button>");
$("body").on('click', '#' + count, function() {
count++;
$("body").html($("body").html() + "<button id=\"" + count +"\">" + count +"</button>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Using .on() you can define your function once, and it will execute for any dynamically added elements.
for example
$(document.body).on('click', 'body #' + count, function() {
//do something
});
The .on() works with elements that are added later to the page, only when it is bound to an element that already exists at runtime. In your example, the element that you're binding to .on() does not exist at runtime, hence there is no way that jQuery can bind the handler to dynamically added elements. Remember that $el.on('click') is basically the same as $el.click().
What you want to do differently, is to bind the .on('click') to an element, say the <body> element, that is always present at runtime—that means you should change this:
$("body #" + count).on("click", function () {...});
...to this:
$("body").on("click", "#" + count, function () {...});
The .on() accepts an additional argument that allows the body to check, when it receives a click event, which element did it "bubble up" from. In this case, you tell the body:
Listen to the click event
When a click event is detected, execute the callback only when I know it has originated from an element with the ID of count
In your script click event not called after the button element created. Try the below script.
var count = 1;
$("body").html("<button id=\"" + count + "\">1</button>");
$("body #" + count).on("click", btnListener);
function btnListener() {
count++;
$("body").html($("body").html() + "<button id=\"" + count + "\">" + count + "</button>");
$("body #" + count).on("click", btnListener);
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<script src="script.js"></script>
</body>
</head>

Is it a scope issue?

I add a close button to the card. I try this code but the close button seems not working.
$('#add-pet').on('click', e => {
// Grab info from the form
let $name = $('#pet-name').val();
let $species = $('#pet-species').val();
let $notes = $('#pet-notes').val();
let $newPet = $(
'<section class="six columns"><div class="card"><p><strong>Name:</strong> ' + $name +
'</p><p><strong>Species:</strong> ' + $species +
'</p><p><strong>Notes:</strong> ' + $notes +
'</p><span class="close">×</span></div></section>'
);
// Attach the new element to the page
$('#posted-pets').append($newPet);
});
$('.close').on('click', function() {
$(this).parent().remove();
});
However, when I move this code:
$('.close').on('click', function() {
$(this).parent().remove();
});
right after the $('#posted-pets').append($newPet);
Then it works OK.
Why it is like that?
Whenever you want to make an event for an element which may be appended via jquery, you can try:
$(document).on('click', '.close', function() {
$(this).parent().remove();
});
It works after you appending span.close tag. Even if outside the scope
$('#add-pet').on('click', /*...*/);
Update:
You can also try:
$('#add-pet').on('click', e => {
let close_tag = $('<span>').addClass('close');
// do stuff...
// set event
close_tag.on('click', function () {
$(this).parent().remove();
});
$('#posted-pets').append(close_tag);
});
When the close function is outside of the div, it's trying to attach to existing .close elements and the element you are trying to attach to doesn't exist at that point in time. You need to do it inside because you need to have the $newPet element actually created before you can attach to it.
$('.close') will search in the dom.
If you haven't appended your html, then it can't be found by jQuery

Duplicated button doesn't work click();

I have the code below:
$(document).ready(function(){
var counter = 0;
$("button").click(function() {
$('body').append("<button>generate new element "+(counter++)+"</button>")
});
});
JSFiddle
When you click duplicated button, it won't duplicate another button again besides the original button only works.
Why cannot listen this event to duplicated buttons?
EDITED:
//Click button event DELEGATION
$(document).on("click",".choice", function() {
var userChoice = $(this).attr("value");
//EXTERNAL SPAGUETTHI CODE
};
Need to grab "value" of this button when it's clicked.
You need delegation: catching the clicks on the parent but only those that were made on button elements. $("button") selects the existing buttons on the page, $(document) (you can replace document with your button container) will select the container and by using $(document).click("button", ...) you delegate the clicks on the buttons.
$(document).ready(function() {
var counter = 0;
$(document).click("button", function(e) {
var value = $(e.target).attr("data-value"); // or .data("value")
alert(value);
$('body').append("<button data-value=\"" + ++counter + "\">generate new element " + counter + "</button>")
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button data-value="initial-button">generate new element</button>
Here are some other similar answers I posted:
Direct and delegated events
Delete dynamic elements
Function not working second time

Why is my JQuery function not triggered on a cloned element when the event becomes "true"?

I have been making this form that must enable the back-end user to create new questions for users to answer. The form is cloned and appended to a div (selector #content) successfully after the first .on(click) event, but it won't duplicate the form again if the cloned button is pressed. The .on(change) event applied to my drop-down selection does change the content of respective divs like it is supposed to, but only on the original form.
Here's the JQuery code:
$(document).ready(function () {
$('.addAnswer').on("click", function () {
var idx = $('#mp div[name^="antwoord"]:last').index() + 1;
$clone = $('#mp div[name^="antwoord"]:first').clone(true, true).attr('class', 'answer content_' + idx);
$('.removeAnswer').show;
$('#mp').append($clone);
$('.answer:last').each(function () {
$('b:last').empty();
$('b:last').prepend(String.fromCharCode(64 + idx) + ". ")
$('.addAnswer').on("click", function () {
idx++;
});
});
if (idx == 2) {
$('.removeAnswer').show();
}
});
$('.nextq').click(function () {
var newqid = $('#content form:last').index() + 1;
$('.done, .nextq, .remove').hide();
$('#content').append('<hr>');
$('#content').append($('form').html()).attr('class', 'q_' + newqid);
$('.nextq').on("click", function () {
newqid++;
});
$('.done:last, .nextq:last, .remove:last').show();
return false;
});
$('.group').hide();
$('#text:last').show();
$('.select:last').on("change", function () {
$('.group').hide();
$('#' + $(this).val() + ':last').fadeIn();
$('button.' + $(this).val() + ':last').fadeIn();
});
});
Because I thought posting the whole HTML template would be a tad bit too much, I provided a JSFiddle for you people.
One extra question for the ones that are feeling kind: In the JQuery code it is seen that the contents of the HTML are being parsed using .html() and appended with .append.(Line 33 on the JSFiddle) As the .on(change) function switches the contents of the divisions it should change, .html() sees those changes and takes those along with it. I'd like the .on(click) function to append the div's content in its original state, unchanged by the changes made beforehand by the back-end user. Any help with this would be much obliged.
In order to have jQuery trigger on new elements you would do something like
$( document ).on( "click", "<your id or class>", function() {
//Do stuff
});

Categories

Resources