Adding onclick event to dynamically created buttons in javascript without using library - javascript

I want to add onclick event to dynamically created buttons based on data. I tried to add the event in the same loop as the buttons are created. but only the last button onclick event works and the rest doesnt work.
if i add a separate loop to add the events, it works for all buttons as expected. I want to know why I couldn't achieve it in the same loop.
the commented block is the code i tried to add inside the loop for adding event.
Also, please suggest if there is any better way to work this(just want to try without libraries, no particular reason).
Code:
function a() {
var objContent = document.getElementById('content')
var fruits = ['apple', 'banana', 'orange', 'grapes']
for (var i in fruits) {
var buildHtml = `<div id="content">
<div id="editsection">
<button id="${fruits[i]}" class="buttons" value="${fruits[i]}">${fruits[i]}</button>
</div>
<div id="deletesection">
</div>
</div>`
objContent.innerHTML += buildHtml
**/* var objFruitButton = document.getElementById(fruits[i])
objFruitButton.addEventListener("click", function (){
onClick(objFruitButton.value)
}, false); */**
}
fruits.forEach(function(i) {
var objFruitButton = document.getElementById(i)
objFruitButton.addEventListener("click", function() {
onClick(objFruitButton.value)
})
})
}
function onClick(x) {
console.log("value:", x);
}
a();
<div id="content"></div>

Related

Trouble Repeating Button Functionality Across Various Data in Javascript [duplicate]

I have been using oneclick methods forever and am rewriting my website and want to switch to a modern of doing things (event listeners)
I understand how to add an event listener.
Const button = document.getElementById('button');
button.addEventListener('click');
I could loop through all the buttons but how would I properly event delegate?
Basically I have a table. And I want to target every button in it that has a specific class “edit-user” and listen for any of those buttons being clicked.
Thanks, but confused at best way to event delegate and target specific elements and having one event listener for entire table. Seems bad to add 50 different listeners for each button.
Event Delegation works on this way:
( more easy with the use of element.matches )
<table id="my-table">
...
<tr>
<td>
<button class="edit-user">aaa</button>
...
<tr>
<td>
<button class="edit-user">bbb</button>
...
<tr>
<td>
<button class="other-class">ccc</button>
...
const myTable = document.querySelector('#my-table')
myTable.onclick = e =>
{
if (!e.target.matches('button.edit-user')) return // reject other buttons
console.log( e.target.textContent) // show "aaa" or "bbb"
// ...
}
Here is an example, note that you can add new buttons dynamically and it still works the way that's not possible when you add an event listener to each element, so in my example there is a button "add more buttons" that adds more buttons dinamically to demonstrate that all are clickable the same way.
var butCont = document.querySelector("#buttons-container");
butCont.onclick = function(e) {
if(e.target.nodeName === "BUTTON") {
//to prevent hiding the snippet with the console
console.clear();
console.log(e.target.textContent);
}
};
for(var i = 0;i < 50; i++) {
butCont.innerHTML += `<button>${i + 1}</button>`;
}
//don't worry the .querySelector will get the first button which is the add more buttons one and not other button
document.querySelector("button").onclick = function() {
butCont.innerHTML += `<button>${i += 1}</button>`;
}
#buttons-container {
width: 300px;
}
button {
width: 30px;
height: 30px;
}
<button style="width: 300px;">add more buttons</button>
<div id="buttons-container">
</div>

Change location.href with jQuery

I need to change the location.href of some URLs on my site. These are product cards and they do not contain "a" (which would make this a lot easier).
Here is the HTML:
<div class="product-card " onclick="location.href='https://www.google.com'">
I mean it is pretty simple, but I just cannot get it to work. Did not find any results from Google without this type of results, all of which contain the "a":
$("a[href='http://www.google.com/']").attr('href', 'http://www.live.com/')
Any ideas on how to get this to work with jQuery (or simple JS)?
I cannot change the code itself unfortunaltely, I can just manipulate it with jQuery and JS.
To change the onClick for all the class='product-card', you can do something like this:
// All the links
const links = document.getElementsByClassName('product-card');
// Loop over them
Array.prototype.forEach.call(links, function(el) {
// Set new onClick
el.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
});
<div class="product-card " onclick="location.href='https://www.google.com'">Test</div>
Will produce the following DOM:
<div class="product-card " onclick="location.href = 'http://www.live.com/'">Test</div>
Another option, is to loop over each <div> and check if something like google.com is present in the onClick, if so, we can safely change it without altering any other divs with the same class like so:
// All the divs (or any other element)
const allDivs = document.getElementsByTagName('div');
// For each
Array.from(allDivs).forEach(function(div) {
// If the 'onClick' contains 'google.com', lets change
const oc = div.getAttributeNode('onclick');
if (oc && oc.nodeValue.includes('google.com')) {
// Change onClick
div.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
}
});
<div class="product-card" onclick="location.href='https://www.google.com'">Change me</div>
<div class="product-card">Don't touch me!</div>

Get variables from button css in Javascript and use them as id

Hi I need a bit of help modifying my script. What I want to do:
I have a small and easy script. It changes the class of an container so I have influence on the behaviour and looking of the container. In my scenario the buttons open a div with a music player.
My problem is that I need to declare all buttons as a script. The button ID is in my case the onclick function (see code).
So when I have 10 or twenty links I need also everytime to modify the script. My idea is to have a script wich gets feed their variables by id's and classes of containers. So I need not to modify the script file.
// JavaScript Document
function AudioFF() {
var FFplayer = document.getElementById(x);
if (FFplayer.classList.contains("audio-hidden")) {
FFplayer.classList.remove("audio-hidden");
FFplayer.classList.add("audio-shown");
} else {
FFplayer.classList.remove("audio-shown");
FFplayer.classList.add("audio-hidden");
Array.prototype.slice.call(document.querySelectorAll('audio')).forEach(function(audio) {audio.pause();});
}
};
dbbtn.onclick = function() {
x = "deepblue";
AudioFF();
};
swbtn.onclick = function() {
x = "spacewalk";
AudioFF();
};
fbtn.onclick = function() {
x = "forest";
AudioFF();
};
drbtn.onclick = function() {
x = "dreamrhythm";
AudioFF();
};
My idea was to use the same class of a button as an id for the container who needs to fade in with a string. The button has e.g. the class btn_a, btn_b … etc. The containers has the id btn_a, btn_b … I wanted the script to catch the class of the button and use this classname as a variable for getElementById. The closebutton is also using the same script to close the container. Thanks for help :-)
I will recommend to use data attribute instead
example like this:
//register listener like this
var btns = document.querySelectorAll('[data-music]');
btns.forEach(function(elm) {
elm.addEventListener('click', function(e) {
//your function
console.log(this.dataset.music);
})
})
<!--your links-->
<div id="m1"></div>
<div id="m2"></div>
<div id="m3"></div>
<!--just add data-music attribute make it the same with your div id and all set-->
<button data-music="m1">play m1</button>
<button data-music="m2">play m2</button>
<button data-music="m3">play m3</button>
You should be able to set a data tag attribute to the buttons and just read the variable from that:
<button id="myButton" data="variableForMyButton" />
document.getElementById(myButton).onClick = function(e){
x = e.target.getAttribute('data')
}
If multiple params are required you add additional data tags:
<button id="myButton" data="variableForMyButton" data-action="someSweetAction" />
Thanks guys, that was what I was looking for. My function is now like this:
The play button and closebutton are working.
<button data-music="m1">Deep Blue</button>
<div id="m1">Container Content</div>
var btns = document.querySelectorAll('[data-music]');
btns.forEach(function(elm) {
elm.addEventListener('click', function(e) {
//function
var FFplayer = document.getElementById((this.dataset.music));
if (FFplayer.classList.contains("audio-hidden")) {
FFplayer.classList.remove("audio-hidden");
FFplayer.classList.add("audio-shown");
} else {
FFplayer.classList.remove("audio-shown");
FFplayer.classList.add("audio-hidden");
Array.prototype.slice.call(document.querySelectorAll('audio')).forEach(function(audio) {audio.pause();});
}
})
})
And here in jquery. Thanks to you all. You show me the way :-)
jQuery (document).ready(function($){
var btns = $('[data-music]');
$(btns).each(function() {
$('[data-music]').on('click', function(e) {
var FFplayer = $(this).data('music');
$("#" + FFplayer).toggleClass("audio-hidden audio-shown");
});
});
})

Creating multiple event listeners using a loop

Trying to create multiple listeners with a loop. How to make it work?
var buttons = ['one', 'two', 'tree'];
$.each(keys, function(key, value) {
$(value).click(function() {
// do something
});
});
Also, is there a shortcut to not writing key, value when I only need the value?
You are better off putting a delegated event listener on a parent instead of iterating through every button. For example, if you place all your <button> elements inside of a <div> with the id #container, then you can write your listener like this:
$('#container').on('click', 'button', function() {
// do something;
});
Now, every time a button element is clicked within that div, your callback will be invoked. You can also use a class selector in place of 'button' to only listen to elements that have that class.
If you want to make it work by looping then you can use
var buttons = ['.one', '.two', '.three'];
// ---------------- with -------- $.each();
$.each( buttons, function(key, value) {
$(value).click(function() {
// ------------- Do something
});
});
// ------------------ with ----------- for loop
for( var i=0 ; i < buttons.length ; i++ )
{
$(buttons[i]).click(function({
// ------------- Do something
});
}
But why to go this round if just want to assign event
$('.one, .two, .three, #one, #two, #three').click(function() {
// ------------- Do something
});
OR if having variable
var buttons = '.one, .two, .three, #one, #two, #three';
$(buttons).click(function() {
// ------------- Do something
});
AND THATS IT no key, no value, no for, no each
Sounds like you'd be better off assigning the click handler to a button with a specific class name instead of iterating over a list of selectors and assigning a new function inside a loop.
<button class='my-button' id="one">
One
</button>
<button class='my-button' id="two">
Two
</button>
<button class='my-button' id="three">
Three
</button>
and the JS
$('.my-button').click(function() {
var id = $(this).attr('id');
$('body').append("<div>Button " + id + " was clicked</div>");
});
Take a look this fiddle https://jsfiddle.net/4e7rk10L/
In jQuery you can select some elements together, and seperate them using colon ,
var buttons = ['one', 'two', 'tree'];
$(buttons.join()).click(function(){
// Do something
})
In this example I'm using join to convert the array to one,two,three then I add one event listener to all those element
If you really want loop (This was your question) you can do this:
for(var i=0;i<buttons.length;i++)
$(buttons[i]).click(function({
// Do something
})

Do I need to create multiple functions for multiple actions or can they all be housed in the same function?

I'm working on a script to simulate a page change in a Questionnaire I'm building. I figured maybe I could use a bunch of "if" statements to house all the logic but it's not working right, before I go and create separate functions I'd like to know if it's possible to put them all in one single function.
So far this is the script
function pageChange(){
var chng1 = document.getElementById("p1next");
var chng2a = document.getElementById("p2back");
var chng2b = document.getElementById("p2next");
var chng3a = document.getElementById("p3back");
var chng3b = document.getElementById("p3next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
var pg3 = document.getElementById("page03");
if (chng1.click){
pg1.style.display="none";
pg2.style.display="block";
}
if (chng2a.click){
pg1.style.display="block";
pg2.style.display="none";
}
the "p1next, p2back, p2next etc." are IDs I gave the buttons on the pages, which I have in DIVs that I respectively named "page01, page02, page03 etc."
Without the 2nd if statement the script works exactly how I want it, it changes the display for "page01" to none and the div for "page02" to block. When I add the second if statement it doesn't work.
The reason I want to do it like this rather than making actual pages is because I don't want the data to get lost when they load another page. Am I on the right track or do I need to create a new function for each page?
Not exactly on the right track, you should use onclick events, instead of if (x.click) like this:
var chng1 = document.getElementById("p1next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
// Events
chng1.onclick = function(){
pg1.style.display="none";
pg2.style.display="block";
};
This will save your function until the element is clicked and then execute that function. In your case, it is executed on page load, and at that moment the user is not clicking anything.
Why not try something like this:
HTML:
<div class="page" data-pg="1">...</div>
<div class="page" data-pg="2">...</div>
<div class="page" data-pg="3">...</div>
<input id="btnPrev" type="button" value="Prev" />
<input id="btnNext" type="button" value="Next" />
jQuery:
var pageNum = 1;
$(document).ready(function () {
$("#btnPrev").on("click", function () { ChangePage(-1); });
$("#btnNext").on("click", function () { ChangePage(1); });
ChangePage(0);
});
function ChangePage(p) {
$(".page").hide();
pageNum += p;
$(".page[data-pg='" + p + "']").show();
$("#btnPrev").removeAttr("disabled");
$("#btnNext").removeAttr("disabled");
if (pageNum === 1) $("#btnPrev").attr("disabled", "disabled");
if (pageNum === $(".page").length) $("#btnNext").attr("disabled", "disabled");
}
That way you can easily grow your number of pages without changing the script. My apologies by the way for doing this in jQuery.
Update:
Have a lot of time on my hands today and have not coded for while using vanilla Javascript. Here's the version of the code using plain js: https://jsfiddle.net/hhnbz9p2/

Categories

Resources