Error in my code is, I add condition to run a JavaScript function only one time but when I add if else logic web page can open all sections
here is my code logic:
let count = 0;
window.addEventListener('scroll', fade);
function fade()
{
if (count < 1)
{
let animation=document.querySelectorAll('.fade');
for (let i=0; i<animation.length; i++)
{
let windowheight=window.innerHeight;
let top=animation[i].getBoundingClientRect().top;
if (top < windowheight)
{
animation[i].classList.add('visible');
}
else
{
animation[i].classList.remove('visible');
}
}
}
else
{
return ;
}
count++;
}
Since you only need to handle the event once,
window.addEventListener('scroll', fade, {once: true});
You can safely remove count variable and if...else.
Related
https://jsfiddle.net/h0avkn8p/is my entire code
When you play the game twice, you will see that the correct square position from the last game stays white, does anyone know where the problem is? I think it is coming from this part of my code.
function genSquareColors(){
if(arr.length > 0){
arr.splice(0, arr.length);
}
for(let i = 0; i < 5; i++){
arr.push(genWrong()); // generates five incorrect squares
}
arr.push(answer);
scramble(arr);
console.log(arr);
return arr;
}
function setColor(){
for(let i = 0; i < squares.length; i++){
squares[i].style.backgroundColor = arr[i];
}
}
function colorSquares(){
for(let i = 0; i < squares.length; i++){
squares[i].addEventListener("click", function(){
var clicked = this.style.backgroundColor;
if(clicked === answer){
alert("You won!");
reset();
this.style.backgroundColor = setColor();
} else {
this.style.backgroundColor = "#FFFFFF";
tries--;
}
});
}
}
I see that here:
function colorSquares(){
for(let i = 0; i < squares.length; i++){
squares[i].addEventListener("click", function(){
You're attaching a new event listener to each square every time the game runs. So, starting on the second game, a click will produce two results for each listener. On the third game, there will be three results - etc. So a click can result in a square both "winning", and being colored white.
Either save a reference to each listener in a persistent variable, then call removeEventListener with each one of them - or use .onclick instead, so that only the latest assignment is kept.
function colorSquares(){
for(let i = 0; i < squares.length; i++){
squares[i].onclick = function(){
var clicked = this.style.backgroundColor;
if(clicked === answer){
alert("You won!");
reset();
this.style.backgroundColor = setColor();
} else {
this.style.backgroundColor = "#FFFFFF";
tries--;
}
};
}
}
Whats going on here is your event listener is being created on the same items over and over and never being cleaned up.
If you console.log out the in the event IE.
for (let i = 0; i < squares.length; i++) {
squares[i].addEventListener("click", function() {
var clicked = this.style.backgroundColor;
console.log("On No!");
if(clicked === answer) {
alert("You won!");
reset();
setColor();
} else {
this.style.backgroundColor = "#FFFFFF";
tries--;
}
});
}
}
You will notice that the click event is being called many times.
The fix would be to store the event once its applied and then if the event is set, reset it. IE.
https://jsfiddle.net/djbkmqe6/
Or apply the event only once ie.
https://jsfiddle.net/ebv1yLdt/
I've been having issues where when I try to remove an event from the buttons it seems to only be removing the event for the one-button even though I have looped through the buttons and removed the event.
thank you.
function ChangeQuestions() {
let currentQuestion = getQuestion(); //another function to get the question from an array - returns an object with questions, answers and correctAnswer
const correctAnswer = currentQuestion.correct;
console.log(currentQuestion);
if (questionsArray.length === 0) {
//If the array is empty push the questions again
questionsArray.push(firstQuestion, secondQuestion, thirdQuestion);
}
document.querySelector('.question-header').textContent = currentQuestion.questions;
for (let i = 1; i < 4; i++) {
document.querySelector('.btn-Ans-' + i).textContent = currentQuestion.answers[i - 1];
document.querySelector('.btn-Ans-' + i).addEventListener('click', function checkAns(e) {
if (e.target.innerHTML === correctAnswer) {
score++;
console.log(score);
removeEvent('click', checkAns);
ChangeQuestions();
} else {
console.log(score);
removeEvent('click', checkAns);
ChangeQuestions();
}
});
}
}
function removeEvent(event, func) {
for (let i = 1; i < 4; i++) {
document.querySelector('.btn-Ans-' + i).removeEventListener(event, func);
}
}
With
for (let i = 1; i < 4; i++) {
document.querySelector('.btn-Ans-' + i).addEventListener('click', function checkAns(e) {
A new checkAns function is created inside every iteration of the loop, and removeEventListener must be passed the exact same function that addEventListener was called with. Since the different loop iterations have different functions passed into their respective addEventListener calls, the removeEvent function appears to only affect the element that was clicked, and none of the rest.
Here's a more minimal example:
const fns = [];
for (let i = 0; i < 2; i++) {
const foo = () => console.log('foo');
fns.push(foo);
window.addEventListener('click', foo);
}
// Not the same function:
console.log(fns[0] === fns[1]);
I'd add just a single listener to the container instead, and use event delegation to check which element was clicked on:
btnContainer.addEventListener('click', function handler(e) {
if (!e.target.matches('[class^="btn-Ans"]')) {
return;
}
btnContainer.removeEventListener('click', handler);
if (e.target.innerHTML === correctAnswer) {
score++;
}
console.log(score);
ChangeQuestions();
});
where btnContainer is a container for your btn-Ans-s.
This one uses For Loop
After you click on another button they don’t change back to the play button, and instead they stay on pause. The audio pauses without an issue, it’s just the buttons that don’t change back for some reason.
https://jsfiddle.net/pezuLqvo/85/
function hideAllButtons(button) {
const buttons = button.querySelectorAll(".play, .pause, .speaker");
for (let i = 0; i < buttons.length; i += 1) {
hide(buttons[i]);
}
}
function pauseAllButtons(buttons) {
for (let i = 0; i < buttons.length; i += 1) {
if (isPlaying(buttons[i])) {
showPlayButton(buttons[i]);
}
}
}
function showPauseButton(button) {
const pause = getPause(button);
pauseAllButtons(button);
hideAllButtons(button);
show(pause);
button.classList.add("active");
}
Looking at how this one was set up, are you able to determine what I would change in the above code to fix that issue?
This one uses forEach
https://jsfiddle.net/pezuLqvo/84/
function hideAllButtons(button) {
button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
}
function pauseAllButtons() {
const buttons = document.querySelectorAll(".playButton");
buttons.forEach(function hidePause(button) {
if (isPlaying(button)) {
showPlayButton(button);
}
});
}
function showPauseButton(button) {
const pause = getPause(button);
pauseAllButtons();
hideAllButtons(button);
show(pause);
button.classList.add("active");
}
This was the answer:
https://jsfiddle.net/pezuLqvo/93/
function pauseAllButtons() {
const buttons = document.querySelectorAll(".playButton");
for (let i = 0; i < buttons.length; i += 1) {
if (isPlaying(buttons[i])) {
showPlayButton(buttons[i]);
}
}
}
i m very much new to programming with JavaScript and would love to gain more experience, my problem isn't actually a problem, it more like of optimizing a code, I've been working on making what so called a "pagination" a dot navigation. you can find my code example in this code pen https://codepen.io/Tarek-Chentouf/pen/ajqXpW . My code goes as follow:
"use strict";
var buttons = document.querySelectorAll('.button__outline');
function reset() {
for (let i = 0; i < buttons.length; i++) {
buttons[i].classList.remove('active');
}
}
function addActive() {
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
if (i == 0) {
reset();
buttons[0].classList.add('active');
}
if (i == 1) {
reset();
buttons[1].classList.add('active');
}
if (i == 2) {
reset();
buttons[2].classList.add('active');
}
if (i == 3) {
reset();
buttons[3].classList.add('active');
}
});
}
}
addActive();
my Question goes as follow is there a better way to achieve the same result without having to repeat the if statement?.
Thank you all in advance.
For the general case, you could simply access buttons[i] instead of if (i == 0) ... buttons[0] ... if (i == 1) ... buttons[1] ...:
function addActive() {
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
reset();
buttons[i].classList.add('active');
});
}
}
But you could make the code cleaner and DRY-er with a forEach - instead of accessing an index of the buttons collection, abstract the button being iterated over into a variable of its own:
function addActive() {
buttons.forEach(button => {
button.addEventListener('click', () => {
reset();
button.classList.add('active');
});
});
}
Or, as Patrick Roberts suggested, you might move all the classList changes into the reset function and use event delegation on the container (that way you only need one listener, rather than many):
document.querySelector('.container').addEventListener('click', ({ target }) => {
if (!target.matches('.button__outline')) return;
reset(target);
});
const buttons = document.querySelectorAll('.button__outline');
function reset(showButton) {
buttons.forEach(button => {
button.classList.remove('active');
})
showButton.classList.add('active');
}
reset(buttons[0]);
Hi I some javascript code written to quiz the user on 5 questions and then in theory output their score. As far as I can tell the questions are being scored, I just can't figure out how to output the response. I am having no issues fetching the correct html elements and displaying them. I believe the issue is in the looping elements of the window.onload function. The code is below,
<script type="text/javascript">
var rand = 0;
var right = 0;
window.onload = function () {
reset();
Rrand();
var rangQ = document.getElementById('area').getElementsByClassName('divide');
correct = document.getElementsByTagName('a'), i = 0;
for (i; i < correct.length; i++) {
if (correct[i].className == 'correct') {
correct[i].onclick = function () {
right++;
reset();
Rrand();
}
}
else if (correct[i].className != 'correct') {
correct[i].onclick = function () {
right--;
reset();
Rrand();
}
}
}
}
function Rrand() {
var rangQ = document.getElementById('area').getElementsByClassName('divide');
rangQ[rand].style.display = '';
rand++;
}
function reset() {
var rangQ = document.getElementById('area').getElementsByClassName('divide');
for (var i = 0; i < rangQ.length; i++) {
rangQ[i].style.display = 'none';
}
}
document.write(right);
</script>
window.onload is not executed immidiately. you are writing output, but variable right is changed after that.
you need to either move line
document.write(right);
into window.onload as last line (or after loop) or figure out other way that will be best for you