Javascript memory card game last card not flipping - javascript

Hi I have a memory game that has a demo here.
https://kuochye.github.io/memorygame/
I have a issue with the last card not flipping over and can't figure out why.
document.querySelectorAll(".flip-container").forEach(card => card.classList.add("clicked"));
setTimeout(function () {
document.querySelectorAll(".flip-container").forEach(card =>
card.classList.remove("clicked"));
}, 30000);
^ This was what I did to show the cards for 30 secs before it flips down. But somehow the last card is not showing.
// Build single card
var buildCardNode = function (index, value, isRevealed, width, height) {
var flipContainer = document.createElement("li");
var flipper = document.createElement("div");
var front = document.createElement("a");
var back = document.createElement("a");
flipContainer.index = index;
flipContainer.style.width = width;
flipContainer.style.height = height;
flipContainer.classList.add("flip-container");
if (isRevealed) {
flipContainer.classList.add("clicked");
}
flipper.classList.add("flipper");
front.classList.add("front");
front.setAttribute("href", "#");
back.classList.add("back");
back.classList.add("card-" + value);
back.setAttribute("href", "#");
flipper.appendChild(front);
flipper.appendChild(back);
flipContainer.appendChild(flipper);
flipContainer.addEventListener('click', handleFlipCard);
document.querySelectorAll(".flip-container").forEach(card => card.classList.add("clicked"));
setTimeout(function () {
document.querySelectorAll(".flip-container").forEach(card =>
card.classList.remove("clicked"));
}, 30000);
return flipContainer;
};

What you're doing is looking for every card that has already been added and flipping it. That would be fine, but you're doing it before adding each card to the document. So for each card added it finds every card added previously and flips it.
You want to be doing one of two things instead:
a. Flip all cards after they have been added to the document (by moving that first piece of code out of buildCardNode function to where it is called from).
b. Flip each card directly before it is added to the document (instead of using document.querySelectorAll.forEach, you use flipContainer.classList.add/remove).

Related

Why is my for loop not pulling the correct data from my array of objects?

I have successfully got my jQuery to load individual data from my array of objects but when I tried to add a jQuery click event to enable a toggle feature (that loads the image of the div into a bigger 'fullscreen' view) it only loads the very last array item's data.
Sample of my array of objects I'm calling allPictures:
var allPictures = [
{
name: "Elevated",
number: 0,
desc: "Hand Forged Steel Sculpture. Dimensions: 18\" diameter 16\” Height. Finish: Blue Opal, powdered pigment",
tag: "Sculpt"
},
{
name: "Paradise",
number: 1,
desc:"Hand Sculpted Auto Entry Gate. Material: Aluminum. Finish: Marine grade primer/Bronze Verde gre Faux/Hand Painted Bird of ParadiseFlowers",
tag:"Metal"
},
{
name: "Herculean Trellis",
number: 2,
desc:"Rose bush Trellis; Hand Forged. Material: Steel. Dimensions: 6’6”Hx3’9”W Weight: 340lbs. Finish: Bronze highlight rub/Bees wax",
tag:"Metal"
},
{
name: "Modern Cable Railing",
number: 3,
desc:"Exterior Stainless Steel Cable Railing. Material: 304 Stainless Steel structure/316 S.S. Cable hardware. Dimensions: 3’6”Hx3”Wx270 linear ft. Finish: Epoxy Primer/Polyurethane",
tag:"Metal"
}]
Relevant for loop from same JS file:
// on PORTFOLIO page, this code loops through ALL PICTURES WITHIN div's
for (i=0;i<allPictures.length;i++) {
$imgNum = allPictures[i].number;
$imgTitle = allPictures[i].name;
$imgDesc = allPictures[i].desc;
$newDIV = $('<div>');
$newDIV.addClass("image-holder");
$newDIV.attr("onclick","toggleView()");
// create newPICTURE
$newPICTURE = $('<img>');
//Change the src using jQuery's attr method + the allPics number
$newPICTURE.attr("src", `images/portfolio/img\ (${$imgNum}).jpg`);
// append PIC to DIV
$newDIV.append($newPICTURE);
// creating infoOverlay
$newOVERLAY = $('<div>');
$newOVERLAY.addClass("info-overlay");
$newOVERLAY.text(allPictures[i].name);
$newDIV.append($newOVERLAY);
// THIS is the function I'd like to change all the relevant info for the toggled fullscreen overlay
$newDIV.click(function(){
$('#centerpiece-img').attr('src',`images/portfolio/img\ (${$imgNum}).jpg`)
$('#centerpiece-title').text($imgTitle);
$('#centerpiece-desc').text($imgDesc);
});
// append DIV to container
$('#art-display').append($newDIV);
}
I'm tired and this is my first post, so sorry If I haven't formatted this post perfectly.
toggleView method on different script/js file - toggle.js (this is EVERYTHING on toggle.js):
function toggleView() {
console.log('toggle.js connected')
// display OVERLAY
var viewerOverlay = document.getElementById('viewerOverlay');
if (viewerOverlay.style.display === 'none') {
viewerOverlay.style.display = "block";
} else {
viewerOverlay.style.display = "none";
}
}
function closeNav() {
document.getElementById("viewerOverlay").style.display = "none";
}
this is a pic of it CORRECTLY loading the right image in the thumbnails
this is the image that loads when I click on "Elevate" (the 1st image)
EDIT: Added photos and changed array to hopefully communicate my problem better.
EDIT2: Added the toggleView() method
Try this one...I just your code copy and modify code..
// on PORTFOLIO page, this code loops through ALL PICTURES WITHIN div's
for (i=0;i<allPictures.length;i++) {
$imgNum = allPictures[i].number;
$imgTitle = allPictures[i].name;
$imgDesc = allPictures[i].desc;
$newDIV = $('<div>');
$newDIV.addClass("image-holder");
$newDIV.attr("onclick","toggleView()");
$newDIV.attr("data-imagePath",`images/portfolio/img\ (${$imgNum}).jpg`);
$newDIV.attr("data-imageTitle",$imgTitle);
$newDIV.attr("data-imgDesc",$imgDesc);
// create newPICTURE
$newPICTURE = $('<img>');
//Change the src using jQuery's attr method + the allPics number
$newPICTURE.attr("src", `images/portfolio/img\ (${$imgNum}).jpg`);
// append PIC to DIV
$newDIV.append($newPICTURE);
// creating infoOverlay
$newOVERLAY = $('<div>');
$newOVERLAY.addClass("info-overlay");
$newOVERLAY.text(allPictures[i].name);
$newDIV.append($newOVERLAY);
// THIS is the function I'd like to change all the relevant info for the toggled fullscreen overlay
}
just write in your function
function toggleView() {
console.log('toggle.js connected')
// display OVERLAY
var viewerOverlay = document.getElementById('viewerOverlay');
if (viewerOverlay.style.display === 'none') {
imageData=$(this).data('imagePath');
imageTitleData=$(this).data('imageTitle');
imageDescData=$(this).data('imgDesc');
$('#centerpiece-img').attr('src',imageData)
$('#centerpiece-title').text(imageTitleData);
$('#centerpiece-desc').text(imageDescData);
viewerOverlay.style.display = "block";
} else {
viewerOverlay.style.display = "none";
}
}
Try using the code below, we have comment the second click function on 'newDIV'. We are utilizing only toggleView function for updating image description.
for (i=0;i<allPictures.length;i++) {
$imgNum = allPictures[i].number;
$imgTitle = allPictures[i].name;
$imgDesc = allPictures[i].desc;
//adding image description as data-attr
$newDIV = $(`<div data-imgnumber='${$imgNum}' data-desc='${$imgDesc}' data-title='${$imgTitle}'>`); // Adding current iteration number
$newDIV.addClass("image-holder");
$newDIV.attr("onclick","toggleView()");
// create newPICTURE
$newPICTURE = $('<img>');
//Change the src using jQuery's attr method + the allPics number
$newPICTURE.attr("src", `images/portfolio/img\ (${$imgNum}).jpg`);
// append PIC to DIV
$newDIV.append($newPICTURE);
// creating infoOverlay
$newOVERLAY = $('<div>');
$newOVERLAY.addClass("info-overlay");
$newOVERLAY.text(allPictures[i].name);
$newDIV.append($newOVERLAY);
// THIS is the function I'd like to change all the relevant info for the toggled fullscreen overlay
/*
As are showing selected image data in toggleView function so, REMOVE THIS CODE
$newDIV.click(function(){
$('#centerpiece-img').attr('src',`images/portfolio/img\ (${$imgNum}).jpg`)
$('#centerpiece-title').text($imgTitle);
$('#centerpiece-desc').text($imgDesc);
});
*/
// append DIV to container
$('#art-display').append($newDIV);
}
and here is your updated toggleView function
function toggleView() {
console.log('toggle.js connected')
// display OVERLAY
var viewerOverlay = document.getElementById('viewerOverlay');
if (viewerOverlay.style.display === 'none') {
// Here we are updating selected image data in bigger div
$('#centerpiece-img').attr('src',`images/portfolio/img\ (${this.getAttribute("data-imgnumber")}).jpg`)
$('#centerpiece-title').text(this.getAttribute("data-title"));
$('#centerpiece-desc').text(this.getAttribute("data-desc"));
viewerOverlay.style.display = "block";
} else {
viewerOverlay.style.display = "none";
}
}

Change the image with JS every time the button is clicked

I am trying to implement the following:
Change the image every time i click the button "next".
Right now the code gives me the very last image from the array book just after I click the button next once. Is there a way it can be done?
HTML code:
<body>
<div class="main_page">
<button type="button" id="start">Start</button>
<button type="button" id="next">Next</button>
</div>
</body>
JS code:
document.addEventListener('DOMContentLoaded', () => {
let book = [
{
name: 'page1',
img: 'img/page1.png'
},
{
name: 'page2',
img: 'img/page2.png'
},
{
name: 'page3',
img: 'img/page3.png'
}
]
const main_page = document.querySelector('.main_page');// with this variable I have conttrol of
// div with class .main_page
let mainImg = document.createElement('img') // similar to HTML tag <img>. this var-ble creates <img> tag in HTML Document
mainImg.setAttribute('src', book[0].img) // making attribute to <img> tag through JavaScript
main_page.appendChild(mainImg);// appending <img> tag to the div with class main_page
let next = document.getElementById('next');
const turnPage = (count) =>{
//if(mainImg.getAttribute("src") == 'img/page2.png') alert("hey")//mainImg.src = {firstpage}
next.addEventListener('click', () => {
if(mainImg.getAttribute("src") == book[count].img){
//alert("hey")
mainImg.src = book[count+1].img
}})
}
for(let i = 0; i< book.length; i++){
turnPage(i);
}
})
You have a few problems with your code, as others have pointed out. As Teemu said, you are adding 3 click listeners to the button. You also need to put the turn page function into your listener, instead of calling it outside. These are the main changes you need:
1: You need to declare a variable outside of the listeners and any loops to keep count of the pages
let count = 0;
2: Add a listener that will call your turnpage function on each click. In that listener, you need to check that the next page isn't greater than the total number of pages before calling turnPage- otherwise you will get an error when the code tries to access the image from a non-existent page.
(You could instead start again at page 1, but as you have a Start button I assumed that you will intend to use that instead of having a continuous loop).
next.addEventListener('click', () => {
if ((count+1) < book.length)
turnPage(count);
count++;
})
3: Finally, your turnPage function just needs to set up the next image
const turnPage = (count) => {
mainImg.src = book[count + 1].img
}
Here is the full working snippet:
document.addEventListener('DOMContentLoaded', () => {
let book = [{
name: 'page1',
img: 'https://lorempixel.com/output/animals-q-c-200-200-9.jpg'
},
{
name: 'page2',
img: 'https://lorempixel.com/output/animals-q-c-200-200-10.jpg'
},
{
name: 'page3',
img: 'https://lorempixel.com/output/animals-q-c-200-200-4.jpg'
}
]
const main_page = document.querySelector('.main_page'); // with this variable I have conttrol of
// div with class .main_page
let mainImg = document.createElement('img') // similar to HTML tag <img>. this var-ble creates <img> tag in HTML Document
mainImg.setAttribute('src', book[0].img) // making attribute to <img> tag through JavaScript
main_page.appendChild(mainImg); // appending <img> tag to the div with class main_page
let next = document.getElementById('next');
// set up your listener to turn the page on each click
next.addEventListener('click', () => {
let count = 0; // declare your variable for page count
// check if the next page is greater than the total number of pages
if ((count+1) < book.length)
turnPage(count);
count++;
})
// your turnPage function
const turnPage = (count) => {
if (mainImg.getAttribute("src") == book[count].img) {
mainImg.src = book[count + 1].img
}
}
})
<body>
<div class="main_page">
<button type="button" id="start">Start</button>
<button type="button" id="next">Next</button>
</div>
</body>
FYI I'm not sure what this line is for, but I've left it in, in case you need it for something you haven't included here:
if (mainImg.getAttribute("src") == book[count].img) {
Also, you could just use the count variable in your pageTurn without passing it in in the click listener. You could check if you are the the end in there - it all depends on how this fits in with the rest of what you need to do.
What Teemu said in the comments is right. I can't comment as my reputation is low. So providing the code here. Just remove turnPage function definition and for loop. And replace it with the code below.
let count = 0, len = book.length;
next.addEventListener('click', () => {
if(mainImg.getAttribute("src") == book[count].img){
count = (count + 1) % len;
mainImg.src = book[count].img
}
});
You can use array to store your image and then display it in your codes
But you also have to make sure you use <img src=""> tag
Example
<img src="" id="myImage">
<br />
<button type="button" id="next">Next</button>
//JavaScript Codes
//Get HTML Elements
let images = [];
let img = document.querySelector("#myImage");
let button = document.querySelector("#next");
let defaultIndex = 0;
//Make a function to be executed once you click the button
function makeIt() {
//Make sure defaultIndex won't be above your array
if (defaultIndex < images.length) {
//Then go to the next image using incrementation
defaultIndex += 1;
//Assign your new value to the img tag
img.src = images[defaultIndex];
}
You can even make previous feature by using decrement.
I hope this will help you. If you find any mistake, feel free to correct!

Function executes only once when using onClick event [javascript]

I am trying to randomly change background image of a div (#reaction-background) after every click of a button (#angry) with onclick event.
However, the background image only changes once after clicking the button.
HTML:
<div class="btn-list">
<a id="angry">ANGRY</a>
<div id="reaction-background"></div>
Javascript:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// random reaction index
var randomIndexReaction = Math.floor(Math.random() * fileNamesReactions.length);
// randomize pictures
document.getElementById("angry").onclick = function() {
document.getElementById("reaction-background").style.background = "url(./img/reactions/angry/" + fileNamesReactions[randomIndexReaction] + ")";
document.getElementById("reaction-background").style.backgroundRepeat = "no-repeat";
document.getElementById("reaction-background").style.backgroundSize = "contain";
}
Your click event handler is, in fact, running every time you click. The problem is that you are only generating a random number once, before any clicks happen and so you set the background image once and further clicks just set the same image over and over.
You need to move the random generator inside of the click callback so that a new random number is generated upon each click.
Also, don't use the onclick property of the element to set up the callback. While this approach works, it's outdated and you should use the more robust and standard .addEventListener() method to set up events.
In addition, do your styling in CSS as much as possible and use CSS classes.
Putting it all together:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// Get your DOM references that you'll use repeatedly just once:
let backgroundElement = document.getElementById("reaction-background");
// randomize pictures
document.getElementById("angry").addEventListener("click", function() {
// You have to get a new random each time the click occurs.
var random = Math.floor(Math.random() * fileNamesReactions.length);
backgroundElement.style.background = "url(./img/reactions/angry/" + fileNamesReactions[random] + ")";
console.log(backgroundElement.style.background);
});
/* Use CSS classes as much as possible as they make code much simpler */
#reaction-background {
background-size:"contain";
background-repeat:"no-repeat";
}
<div class="btn-list">
<a id="angry">ANGRY</a>
<div id="reaction-background"></div>
</div>
Move the random number statement inside the onclick method so that it generate a new number on every click. Please find code below:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// randomize pictures
document.getElementById("angry").onclick = function() {
// random reaction index
var randomIndexReaction = Math.floor(Math.random() * fileNamesReactions.length);
document.getElementById("reaction-background").style.background = "url(./img/reactions/angry/" + fileNamesReactions[randomIndexReaction] + ")";
document.getElementById("reaction-background").style.backgroundRepeat = "no-repeat";
document.getElementById("reaction-background").style.backgroundSize = "contain";
}

javascript value is not updating after onmousevent

I use 1 span tag at the moment.
<span onmouseover="numberOne()" onclick="imgNumber(); return false" onmouseout="noHoverOne()" class="img1 img" id="new-img"> </span>
The span has a "deafult" image, when the mouse goes on the span, another image will be shown, when the mouse leaves the span, the default image will be shown again.
now the javascript:
function numberOne() {
var random2 = Math.floor((Math.random() * 3) + 1);
var random3 = Math.floor((Math.random() * 3) + 1);
do {
var random = Math.floor((Math.random() * 3) + 1);
} while (random === numberOne.last);
numberOne.last = random;
Random numbers are made here. So every time you leave the span and go on the span, there will be a different image.
if (random == 2) {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/molgeld.jpg');";
} else if ((random==random2)==random3) {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/vrijstelling.jpg');";
} else {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/haspel.jpg');";
}
These are the images that will be shown depending on the number
return random;
}
var value = numberOne();
function imgNumber() {
document.getElementById('demo').innerHTML = value;
}
imgNumber();
This is where I am stuck. Before I even have touched the span tag with my mouse, there is already a random number and when I go with the mouse on the span tag, it shows a different image but not a different number. I want to use this number somehow to create a new level for my game. The game is influenced by the chosen image.
So there is a lot going on and it's pretty messy. So please, I would love to hear any kind of constructive feedback.
[EDIT] I will keep the JSfiddle up to date, but there is an error in the preview, it won't display anything. It's still useful Jsfiddle
use a wrapper function where you can call both imgNumber and numberOne
function mouseHover() {
var value = numberOne()
imgNumber(value)
}
function imgNumber(value) {
document.getElementById('demo').innerHTML = value;
}
<span onmouseover="mouseHover()" onclick="imgNumber(); return false" onmouseout="noHoverOne()" class="img1 img" id="new-img"> </span>
Your code is a bit illogical. It seems you want to randomly assign an image to an element background and get a different element each time. So put the image URLs in an array and randomly grab one, ensuring it's different to the last. This means you can add or reduce the images you want to display just by modifying the images array.
Also put all your data in an object rather than using globals, it's just neater. And give your functions names that tell you what they do.
E.g.
var imageData = {
pix: ['http://web-stars.nl/molgeld.jpg',
'http://web-stars.nl/vrijstelling.jpg',
'http://web-stars.nl/haspel.jpg'
],
random: null
}
function changeImage(el) {
// limit do loop just in case data is bad
// Infinite loops are bad...
var len = imageData.pix.length;
var i = len;
do {
var random = Math.random() * len | 0;
} while (i-- && imageData.random == random)
imageData.random = random;
el.style.backgroundImage = imageData.pix[random];
console.log(random, imageData.pix[random]);
}
function updateImageRef() {
document.getElementById('imageRef').textContent = imageData.random;
}
<div id="imageDiv" onmouseover="changeImage(this)" onclick="updateImageRef()">Image div</div>
<div id="imageRef"><div>

Show / Hide images randomly using jQuery

I want to create a function that grabs all the instances of an image class on the page. As default these will be hidden, then randomly after a certain interval show one of those images (can be any image). Then the function will rerun and show another image. (whilst hiding the image that was shown on the first run through.
I've got to this stage with the function (not currently working)
(function randomShow() {
var showDiv = $('.show'),
el = showDiv.eq(Math.floor(Math.random() * showDiv.length));
el.show().delay(2000).show(randomShow);
})();
Thanks
I put together a jsFiddle using divs in place of images to demonstrate (pure js):
http://jsfiddle.net/oogley_boogley/az9gd8wf/
the script:
var divs = document.getElementsByClassName('square');
var arrLength = divs.length;
var randomNumberLimit;
var interval_speed = 1000;
setInterval(function(){
randomNumberLimit = Math.floor((Math.random() * arrLength) + 1);
for(i=0;i<arrLength;i++){
var matchingDiv = divs[i];
if(matchingDiv.id == randomNumberLimit){
matchingDiv.setAttribute("class","showing square blue");
}
if(matchingDiv.id != randomNumberLimit){
matchingDiv.setAttribute("class","hiding square blue");
}
}
}, interval_speed);

Categories

Resources