Guess the winning button by clicking on one of them - Vanilla JS - javascript

You have 3 buttons. On of them, randomly chosen, is a winner. Display if the winning button has been clicked or not. Bonus: Generate n buttons, from which one of them is winner.
My code so far:
let n = 3, buton
for (let i = 0; i < n; ++i) {
buton = document.createElement("button")
document.querySelector("body").appendChild(buton)
buton.id = i
buton.innerText = i
}
let winningButton = 1 // Math.floor(Math.random() * n)
let onClick = function() {
if (winningButton == buton.id) {
alert("Congratulations! You've guessed the button!")
}
}
buton.addEventListener("click", onClick)
Can you help me solve this problem?

In the onClick function, you are not checking against the clicked button, you can use the this keyword to access the button in the event handler
let onClick = function() {
if (winningButton == this.id) {
alert("Congratulations! You've guessed the button!")
}
}
If you use arrow functions this will not be work, so instead, you can use the event object to get the target element
let onClick = (event) => {
if (winningButton == event.target.id) {
alert("Congratulations! You've guessed the button!")
}
}

You can generate a random number when the user clicks.
let n = 3;
let winningButton;
const onClick = function() {
winningButton = winningButton ? winningButton : Math.floor(Math.random() * n);
if (winningButton == this.id) {
alert("Congratulations! You've guessed the button!")
}
}
for (let i = 0; i < n; ++i) {
const buton = document.createElement("button")
document.querySelector("body").appendChild(buton)
buton.id = i
buton.innerText = i;
buton.addEventListener("click", onClick);
}

Related

How do I loop through array elements infinitely, whilst making the current array element visible?

I wish to create a text animation where words are being displayed, one after another and with moderate speed. First I tried achieving this with an onClick event.
const arrayOfWords = ["Acerbity", "Anomalous", "Asymetrical", "Analytical", "Arbritrary"];
const targetOfDisplay = document.querySelector("h1#heading");
const clickElement = document.querySelector("button");
targetOfDisplay.innerHTML = arrayOfWords[0];
let i = 0;
function changeWord(){
if(i < arrayOfWords.length-1) {
i++;
}
else{
i=0;
}
return targetOfDisplay.innerText = arrayOfWords[i];
}
clickElement.onclick = changeWord;
Then I thought about making animation out of it.
I tried working with a timer, but I just can't figure it out.
const arrayOfWords = ["Acerbity", "Anomalous", "Asymetrical", "Analytical", "Arbritrary"];
const targetDisplay = document.querySelector("h1#heading");
let i = 0;
targetDisplay.innerHTML = arrayOfWords[0];
function animateWords(){
if(i < arrayOfWords.length-1) {
i++;
}
else{
i=0;
}
return targetDisplay.innerText = arrayOfWords[i];
}
const currentWord = 0;
const timer = setInterval(onTick,50);
function onTick(){
const change = targetOfDisplay.innerText[currentWord];
currentWord++
if(current === arrayOfWords.length){
complete();
return;
}
}
function complete(){
clearInterval(timer);
timer = null;

When trying to play again after playing again, one of the squares don't color

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/

Javascript Hangman Game Running Functions += Times After Reset

Ok this is my very first ever coding project. I'm self taught and thought creating a hangman game my 2 young kiddos could enjoy would be fun.
I have the game coded and it runs perfectly fine the first time through however, once I click on my reset button to restart the game, my lives start going down by 2 instead of one. After a third reset it goes down by three, and so on. Any console.log()s I put in to check run as many times as well.
I've spend hours racking my brain trying to figure it out and I've looked all over and I'm just not getting what's wrong. I thought about just saying screw it and resort to refreshing the page after every play through to avoid the problem but my brain wont let me do that.
Does anyone have any idea how to fix the problem? I know my code is probably not the most efficient and can definitely use to touch ups, but like I said, this is my first ever project and I know efficiency and skill will come with time and practice (like this). Below is the main chunk of my code.
function gameStart() {
// user writes in a word
pickedWord = prompt('pick a word').toUpperCase();
pickLetterHeading.innerText = 'Pick a Letter'
numLivesSec.hidden = false;
startBtn.disabled = true;
gameIsGoing = true;
resetBtn.disabled = false;
// enables buttons to press
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = false;
}
numLives = 7;
numLivesRemaining.innerText = numLives;
// calls the main game function
gameInProgress();
}
function reset() {
startBtn.disabled = false;
pickedWord = '';
gameIsGoing = false;
resetBtn.disabled = true;
pickLetterHeading.hidden = true;
numLivesSec.hidden = true;
while (guessedSec.firstChild) {
guessedSec.removeChild(guessedSec.firstChild);
}
for (let l = 0; l < alphabet.length; l++) {
document.getElementsByClassName('letterBtnClass')[l].disabled = true;
letters[l].classList.replace('correct', 'letterBtnClass');
letters[l].classList.replace('incorrect', 'letterBtnClass');
}
numLives = 7;
}
function gameInProgress() {
pickLetterHeading.hidden = false;
wordInProgress = '';
for (let i = 0; i < pickedWord.length; i++) {
let lettersToGuess = document.createElement('span');
lettersToGuess.innerText = '_';
guessedSec.appendChild(lettersToGuess);
wordInProgress += '_';
}
for (let btn = 0; btn < letters.length; btn++) {
letters[btn].addEventListener('click', function (e) {
letters[btn].disabled = true;
if (pickedWord.indexOf(letters[btn].innerText) == -1) {
console.log('letter not there!');
numLives -= 1;
numLivesRemaining.innerText = numLives;
console.log('TESTING!')
// checks if you have any tries left. If you have 0, then runs game over
if (numLives == 0) {
console.log('GAME OVER!')
gameIsGoing = false;
pickLetterHeading.innerText = 'You lose. Try again.'
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = true;
}
}
}
// checks if the letter picked matches anything in the chosen word
for (let x = 0; x < pickedWord.length; x++) {
if (letters[btn].innerText == pickedWord[x]) {
// adds class to chosen letter to show you guess correctly
letters[btn].classList.add('correct');
document.getElementsByTagName('span')[x].innerText = pickedWord[x];
wordInProgress[x] = pickedWord[x];
// if picked letter matches something in the chosen word, changes the "_" to the correct letter to show user progress
String.prototype.replaceAt = function (index, char) {
let a = this.split("");
a[index] = char;
return a.join("");
}
wordInProgress = wordInProgress.replaceAt(x, pickedWord[x]);
// when the word is complete. will show you win
if (wordInProgress == pickedWord) {
console.log("WINNER WINNER CHICKEN DINNER!");
pickLetterHeading.innerText = 'YOU WIN!'
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = true;
}
}
} else {
// since you chose incorrectly it adds a class to the button to show a bad choice
letters[btn].classList.add('incorrect');
}
}
})
}
}

removeEventListener only removing single instance

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.

Toggle Event Button

How do you create a button that toggles between to events?
This is the code I've tried
function button (text, callback) {
var but = document.createElement('BUTTON');
var t = document.createTextNode(text);
but.appendChild(t);
var clicks = 0;
but.onclick = function () {
clicks += 1;
if (clicks % 2 !== 0) {
but.addEventListener('click', callback);
} else {
but.removeEventListener("click", callback);
}
}
As James Thorpe suggests in comments this could be done without turning on/off event listeners.
You could just use your existing click event like so:
but.onclick = function () {
clicks += 1;
if (clicks % 2 !== 0) {
callback();
}
}

Categories