Callback Function does not work with for Loop - javascript

Why doesn't the callButtonTwo() function work on all buttons? Only button1 reacts to it?
document.querySelector("h1").addEventListener("click", function() {
alert("Working!");
})
var totalButton = document.querySelectorAll(".testSecond").length;
for (var i = 0; i < totalButton; i++) {
document.querySelectorAll(".testSecond")[i].addEventListener("click", function() {
var buttonNow = this.innerHTML;
callButtonOne(buttonNow);
callButtonTwo(buttonNow);
});
}
function callButtonOne() {
alert("I got clicked!");
};
function callButtonTwo() {
var changeRed = document.querySelector(".testSecond");
changeRed.classList.add("red");
setTimeout(function() {
changeRed.classList.remove("red");
}, 300);
};
.red {
background-color: red;
}
<h1 class="testFirst">Hello World!</h1>
<button class="testSecond button1" type="button" name="button">button1</button>
<button class="testSecond button2" type="button" name="button">button2</button>
<button class="testSecond button3" type="button" name="button">button3</button>
<button class="testSecond button4" type="button" name="button">button4</button>
<button class="testSecond button5" type="button" name="button">button5</button>

While, inside your click handler you have var buttonNow = this.innerHTML; which operates on that button, when you call callButtonTwo you say var changeRed = document.querySelector(".testSecond"); which operates on the first button (no matter which button you click).
You need to tell it which button you are dealing with (e.g. by passing this as an argument)

The problem is, that your querySelector in callButtonTwo just finds the first button because all of them have the same class .testSecond.
One possible solution is to add the reference of the button which should be colored red to the callButtonTwo function and use the reference to add the class name.
It would look like this:
function callButtonTwo(button) {
button.classList.add("red");
setTimeout(function() {
button.classList.remove("red");
}, 300);
};
And you would call it like this: callButtonTwo(this);
Here's a working example based on the code you provided.

Inside callButtonTwo you're querying .testSecond again which will always return the first element in the page with that class. If you want to handle each button differently you should pass the button element as a parameter to callButtonTwo, like so:
var totalButton = document.querySelectorAll(".testSecond").length;
for (var i = 0; i < totalButton; i++) {
document.querySelectorAll(".testSecond")[i].addEventListener("click", function() {
var buttonNow = this.innerHTML;
callButtonOne(buttonNow);
callButtonTwo(this); // 'this' in this case is the clicked button element
});
}
[...]
function callButtonTwo(button) {
button.classList.add("red");
setTimeout(function() {
button.classList.remove("red");
}, 300);
};
I would also consider to change the way you're iterating your elements in order to query the DOM less frequently:
// 'querySelectorAll' returns an array which can be directly iterated using its method 'forEach'
document.querySelectorAll(".testSecond").forEach(function(button) {
button.addEventListener("click", function() {
var buttonNow = this.innerHTML;
callButtonOne(buttonNow);
callButtonTwo(this);
});
});

Related

How to get value from button after it has been clicked

I'm struggling with this assignment: Pin an event listener to the buttons.
Create a function that gets called when one of the buttons is clicked. Check this with a console.log. Make sure the click event is passed to this function.
Make sure you have access to the value of the button clicked in this function. Check this with console.log. The outcome you want to see in the console when you click is: Leopard / Lion / Elephant / Rhino or Buffalo.
fiveButtons = document.getElementsByClassName("big-five-button");
for (var i = 0; i < fiveButtons.length; i++) {
fiveButtons[i].addEventListener("click", function () {
Array.from(fiveButtons).forEach(function (nameButton) {
console.log(nameButton.innerHTML);
})
});
}
This is what I wrote so far. When I'm clicking the button now, the outcome is the text from all the buttons. While I want the outcome to only be "Lion" after the button lion has been clicked.
<h1>The Big Five</h1>
<ul class="big-five-list">
<li class="big-five-list-item">
<button class="big-five-button">Lion</button>
</li> etc.
when creating an addEventListener you can use the event object to target the element clicked, like this:
fiveButtons[i].addEventListener("click", function (event) {
console.log(event.target.innerHTML);
});
You can change the button to include an onclick function like the below:
https://www.w3schools.com/jsref/event_onclick.asp
<!DOCTYPE html>
<html>
<body>
<button onclick="myFunction('Lion')">Lion</button>
<input type="text" value="" id="getValue">
<p id="demo"></p>
<script>
function myFunction(value) {
document.getElementById("getValue").value = value;
}
</script>
</body>
</html>
The onclick function will then have a value inside the () for the function name. This will pass the value you want across to the function and it can be called whatever you want. The above snippet shows an example of how it can be used
Try this solution!
fiveButtons = document.getElementsByClassName("big-five-button");
for (var i = 0; i < fiveButtons.length; i++) {
fiveButtons[i].addEventListener("click", function (item) {
console.log(item.target.innerHTML);
});
}
The function you pass to addEventListener gives an event argument:
fiveButtons = document.getElementsByClassName("big-five-button");
for (var i = 0; i < fiveButtons.length; i++) {
fiveButtons[i].addEventListener("click", function (event) { // use the first argument
console.log('element value:', event.target.value); // log the 'value' of the event target;
// I suspect you want the innerHTML or innerText
console.log('element innerText:', event.target.innerText);
});
}
You can then get the required information from the DOM node in event.target
You don't need the Array.from inside the for loop. You can just do that:
fiveButtons = document.getElementsByClassName("big-five-button");
for (let i = 0; i < fiveButtons.length; i++) {
fiveButtons[i].addEventListener("click", function () {
console.log(fiveButtons[i].innerText);
});
}
EDITED
// Get all the buttons
const fiveButtons = document.getElementsByClassName("big-five-button");
// Iterate through the collection of buttons
// Here is let i = 0 instead of var i = 0, since var has functional scope and let has block scope
// If we used var i = 0 it would not work implicitly because i would exist in the scope of a function,
// and all the event handlers (for each button) would share the same value of i
for (let i = 0; i < fiveButtons.length; i++) {
// For each button register event handler
fiveButtons[i].addEventListener("click", _ => {
// When button is clicked this part of a code is being called
// Because of javascript CLOSURE, it remembers the i value
console.log(fiveButtons[i].innerHTML)
});
}
If this is not understandable please read about closures in javascript.

Variable out of scope but in scope

I have a jquery function that adds an event listener to various elements to execute on click. For some reason, when I try to reference a global variable (daySelected) inside the function, it says it is undefined. Am I missing something?
var daySelected = false;
$('.deal-day').bind('click', function(e) {
console.log("Day Selected: " + daySelected);
if (!daySelected) {
if($(this).hasClass('selected-filter')) {
$(this).removeClass('selected-filter');
var daySelected = false;
} else {
$(this).addClass('selected-filter');
var daySelected = true;
}
}
});
You have multiple var daySelected.
var should be defined only once. Otherwise you're creating new scopes.
As a general fix you could improve the code like:
let daySelected = false; // Feel free to change this boolean
const $dealDay = $(".deal-day"); // Get all buttons with that class
const toggleDaySelectedButtons = () => $dealDay.toggleClass("selected-filter", daySelected);
$dealDay.on("click", function(e) {
daySelected = !daySelected; // Toggle boolean
toggleDaySelectedButtons(); // Handle buttons
});
toggleDaySelectedButtons(); // Do on DOM ready
.selected-filter {background: gold;}
<button type="button" class="deal-day">Filter deal day</button>
<hr>
<button type="button" class="deal-day">Filter deal day</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
I really hope you have only one .deal-day button - otherwise the above will not be ideal

Javascript object methods evaluate functions

first of all, I'm new to javascript.
my question is how can I add an event listener to the button and call the function from the myObj script. I tried to google but I don't know what is the keyword for that. thank you
<div id="my-btn"></div>
<script>
myObj.button('my-btn',{
onClick: function() {
alert('Button is clicked !');
},
onCancel: function() {
alert('You cancel the process !');
}
});
</script>
and my object
var myObj = {
button: function(btnId, methods)
{
var btn = document.getElementById(btnId);
for (var method in methods)
{
if (method.toLowerCase() == 'onclick')
{
//btn.addEventListener('click', function(e) {
//}
// i want to add listener
// and call the function "onClick"
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
}
thank you for your advice.
Here's one way.
<html>
<head></head>
<body>
<div id="my-btn"></div>
</body>
<script>
const myObj = {
button: (btnId, methods) => {
const btn = document.getElementById(btnId);
for (let method in methods) {
const nameLower = method.toLowerCase();
if (nameLower.startsWith('on')) {
btn.addEventListener(nameLower.substr(2), function(e) {
methods[method]();
});
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
};
myObj.button('my-btn',{
onClick: () => alert('Button is clicked !'),
onCancel: () => alert('You cancel the process !')
});
</script>
</html>
We can map the function names to their events by converting to lowercase and stripping off the "on" prefix. So onClick becomes click. You could simplify things by just using the standard event names in your call to myObj.button.
Start by iterating over the functions, map the name and add the event listener. Inside the event listener all we do is call the function provided in the arguments.

Toggle Event Listeners

I am trying to make a function that would allow me to toggle eventListener of an element.
In the example below, I have three buttons: main, on and off. When I click on the on button, the main button becomes functional. After I click off button, the main button should not work anymore (but now it still does).
Now I can achieve a desired behavior by clicking on button for the second time, but I guess it's a bad coincidence and it's not supposed to work that way.
Maybe I should add that I would like to work this out without using jQuery or similar and it needs to be a function, because I am going to use it for a lot of buttons.
(I suspect something with scope causes the problem (clickHandler when calling the function to activate the button is not the same as the clickHandler when calling the function to disable the button), but I can't think of a way to test it.)
// buttons definitions, not important
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButton = document.querySelector("#offButton");
// main function
var toggleButtons = function(toggleVal, button, element) {
var activateButton, clickHandler, disableButton;
// callback function for listener bellow
clickHandler = function() {
document.querySelector(element).classList.toggle("yellow");
};
activateButton = function() {
button.addEventListener("click", clickHandler);
};
disableButton = function() {
button.removeEventListener("click", clickHandler);
};
// when first argument is 1, make the button functional, otherwise disable its functionality
if (toggleVal === 1) {
activateButton();
} else {
disableButton();
}
};
// when onButton is clicked, call main function with arguments
// this works
onButton.addEventListener("click", function() {
toggleButtons(1, mainButton, "body");
});
// this fails to disable the button
offButton.addEventListener("click", function() {
toggleButtons(0, mainButton);
});
.yellow {
background-color: yellow;
}
<button type="button" id="mainButton">mainButton
</button>
<button type="button" id="onButton">onButton
</button>
<button type="button" id="offButton">offButton
</button>
<p>mainButton: toggles background color on click
</p>
<p>onButton: turns on mainButtons's functionality</p>
<p>offButton: supposed to turn off mainButton's functionality</p>
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButon = document.querySelector("#offButton");
var element; // declare the element here and change it from toggleButtons when needed.
function clickHandler() {
document.querySelector(element).classList.toggle('yellow');
}
function activateButton(button) { // You missed this part
button.addEventListener('click', clickHandler);
}
function disableButton(button) { // You missed this part
button.removeEventListener('click', clickHandler);
}
function toggleButtons(value, button) {
if (value === 1) {
activateButton(button); // You missed this part
} else {
disableButton(button); // You missed this part
}
};
onButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(1, mainButton);
});
offButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(0, mainButton);
});
Below code helps to toggle between two functions from an eventListener:
var playmusic=false;
function playSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.currentTime = 0
audio.play()
playmusic=true;
}
function stopSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.pause()
playmusic=false;
}
window.addEventListener('keydown',
function(){playmusic?stopSound():playSound()} )

Button's onclick works but JS event listener does not

I have the following button:
<input type="button" class ="anhalteButton" id="StopButton" value="&#9611 &#9611"/>
which I want to execute the following function (viewsLoop is a global variable):
function clearTDLoop(){
clearInterval(viewsLoop);
}
If I call the function via the button's onclick attribute. i.e.:
onclick="clearTDLoop()" it works flawlessly.
However, I would like to call the function through a JS event listener, but that does not work at all. Do you guys have any idea what I might be doing wrong? My Event Listener Code is attached:
var stopButtonEl = document.getElementById("StopButton");
stopButtonEl.addEventListener("click",clearTDLoop);
Sry for the prior confusion, where my code example stated "StartButton" as the button ID, I copied the wrong ID, the problem persists..
It looks like you have the wrong ID for your event listener:
var startButtonEl = document.getElementById("StartButton");
startButtonEl.addEventListener("click",clearTDLoop);
Should be:
var stopButtonEl = document.getElementById("StopButton");
stopButtonEl.addEventListener("click",clearTDLoop);
I've set an example code for you, please check it:
var tdLoop;
var counter = 0;
var startButton = document.getElementById('startButton');
startButton.addEventListener('click', startTDLoop, false);
var stopButton = document.getElementById('stopButton');
stopButton.addEventListener('click', clearTDLoop, false);
var result = document.getElementById('result');
function startTDLoop() {
tdLoop = setInterval(updateValue, 1000);
}
function updateValue() {
counter++;
result.innerHTML = counter;
}
function clearTDLoop() {
counter = 0;
clearTimeout(tdLoop);
}
#result {
padding: 15px 0 0;
}
<input type="button" class ="anhalteButton" id="startButton" value="Start"/>
<input type="button" class ="anhalteButton" id="stopButton" value="Stop"/>
<div id="result"></div>

Categories

Resources