Click event only works once in querySelectorAll - javascript - javascript

I am currently trying to make a board game in the style of memory (I am self taught, and things like that help me great in understanding javascript). My question is probably basic stuff, but I am new to all of this so I appreciate any help.
My problem is that I have two cards with the same class, and with my code, when I click on first or second one, it only works on the first card.
document.querySelectorAll(".first-card").forEach(container => {
container.addEventListener('click', flipCard)
})
function flipCard() {
document.querySelector(".first-card").classList.toggle("flip")
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
padding: 100px;
display: flex;
}
.first-card,
.second-card {
width: 100px;
height: 150px;
border: 3px solid black;
border-radius: 10px;
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
margin: 10px;
}
.flip {
transform: rotateY(180deg);
}
.front,
.back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.front {
z-index: 2;
transform: rotateY(0deg);
}
.back {
transform: rotateY(180deg);
}
.first-card .front {
background: lightblue;
width: 100%;
height: 100%;
}
.second-card .front {
background: red;
width: 100%;
height: 100%;
}
.first-card .back,
.second-card .back {
background: black;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/CSS" href="memory.css" />
</head>
<body>
<div class="first-card">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="second-card">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="first-card">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="second-card">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<script src="memory.js"></script>
</body>
</html>
Like I said, I am only beginner, so any help or explanation is welcome.
Thank you

It "doesn't work" because in your flipCard function you're getting the first element that matches with the className fist-card. This element will be always the same one. Just change your function to this:
function flipCard(v){
v.currentTarget.classList.toggle("flip")
}

use below
function flipCard(event){
event.target.classList.toggle("flip")
}
evt.currentTarget, which would refer to the parent in this context. So it would not be handy for you I believe.
see mdn for it

Related

How to randomly position (shuffle) multiple divs inside container div with button click - javascript

I'm trying to shuffle (on button click) multiple cards that are in the same container, using only javascript. They basically need to change position every time I click the button.
My idea was to make a function that would on click set their position to absolute, with top and left 0,so they would all overlap. I've managed to do that, but I'm not sure how to proceed and what to do next.
Maybe this isn't even a good way to do it. So if there is simpler solution, feel free to share it with me.
I started learning javascript couple of months ago, so my knowledge is still pretty basic.
Any help is welcome
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/CSS" href="memory.css" />
</head>
<body>
<div class="card-container">
<div class="first-card card" data-value="1">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="second-card card" data-value="2">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="third-card card" data-value="3">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="fourth-card card" data-value="4">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="first-card card" data-value="1">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="second-card card" data-value="2">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="third-card card" data-value="3">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
<div class="fourth-card card" data-value="4">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
</div>
<div class="button-container">
<div>
<button class="flip-all-cards">FLIP ALL</button>
</div>
<div>
<button class="position-button">SHUFFLE CARDS</button>
</div>
</div>
<script src="memory.js"></script>
</body>
</html>
javascript
document.querySelectorAll(".first-card").forEach(container => {
container.addEventListener('click',flipCard)
})
document.querySelectorAll(".second-card").forEach(container => {
container.addEventListener('click',flipCard)
})
document.querySelectorAll(".third-card").forEach(container => {
container.addEventListener('click',flipCard)
})
function flipCard(card){
card.currentTarget.classList.toggle("flip")
}
/*-------------------------------------------------------------------------------*/
document.querySelector(".flip-all-cards").addEventListener("click",function(){
document.querySelectorAll(".card").forEach(container => {
container.classList.toggle("flip")
})
})
document.querySelector(".position-button").addEventListener("click",function(){
document.querySelectorAll('.card').forEach(card => {
card.style.position = "absolute"
card.style.top = "0"
card.style.left = "0"
})
})
css
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
padding: 100px;
}
.card-container{
display: grid;
grid-template-columns: auto auto auto;
padding: 10px;
position: relative;
height: 700px;
}
.first-card, .second-card, .third-card, .fourth-card{
width: 100px;
height: 150px;
border: 3px solid black;
border-radius: 10px;
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
margin: 10px;
}
.flip{
transform: rotateY(180deg);
}
/*
.test-div:hover {
transform: rotateY(180deg);
}*/
.front, .back{
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.front{
z-index: 2;
transform: rotateY(0deg);
}
.back{
transform: rotateY(180deg);
}
.first-card .front{
background: lightblue;
width: 100%;
height: 100%;
}
.second-card .front{
background: red;
width: 100%;
height: 100%;
}
.third-card .front{
background:lime;
width: 100%;
height: 100%;
}
.fourth-card .front{
background:yellow;
width: 100%;
height: 100%;
}
.first-card .back,.second-card .back, .third-card .back, .fourth-card .back{
background: black;
width: 100%;
height: 100%;
}
This is the code I have so far
Instead of trying to rearrange the cards in the DOM, you may consider writing an array in your JS with all the possible colors, then changing the front color of each div with a color from that array.
You can then use a shuffle function like the one here to rearrange the order of the colors in the array.

Static cards won't flip when "flip" function called

I have been trying for hours to get my playing cards to flip when the player clicks on them. When the eventListener is fired it should run the flip function which toggles between the front/backsides of a card. What am I doing wrong?
const playingCards = document.querySelectorAll('.playing-cards');
function flipCard(){;
this.classList.toggle("flip")
}
playingCards.forEach((card) => card.addEventListener("click", flipCard));
.playing-cards{
display: inline-block;
padding: 20px;
position: relative;
cursor: pointer;
}
.playing-cards .flip{
transform: rotateY(180deg);
}
.front-card{
background-color: aqua;
width: 300px;
height: 300px;
transform: rotateX(0deg);
}
.back-card{
background-color: greenyellow;
width: 300px;
height: 300px;
transform: rotateY(180deg);
}
.front-card,
.back-card{
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="index.css">
<title>Document</title>
</head>
<div class="memory-game">
<div class="playing-cards">
<div class="front-card">A</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">B</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">a</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">b</div>
<div class="back-card"></div>
</div>
</div>
<body>
<script src=index.js></script>
</body>
</html>
Answer derived from here
const playingCards = document.querySelectorAll('.playing-cards');
function flipCard() {
this.classList.toggle("flip")
}
playingCards.forEach((card) => card.addEventListener("click", flipCard));
/* The flip card container - set the width and height to whatever you want. We have added the border property to demonstrate that the flip itself goes out of the box on hover (remove perspective if you don't want the 3D effect */
.memory-game {
background-color: transparent;
border: 1px solid #f1f1f1;
perspective: 1000px; /* Remove this if you don't want the 3D effect */
}
/* This container is needed to position the front and back side */
.playing-cards {
display: inline-block;
position: relative;
width: 30px;
height: 30px;
text-align: center;
transition: transform 0.8s;
transform-style: preserve-3d;
cursor: pointer;/*clickable-cursor*/
}
/* Do an horizontal flip when you move the mouse over the flip box container */
.playing-cards.flip {
transform: rotateY(180deg);
}
/* Position the front and back side */
.front-card, .back-card {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden; /* Safari */
backface-visibility: hidden;
}
/* Style the front side (fallback if image is missing) */
.front-card {
background-color: aqua;
color: black;
}
/* Style the back side */
.back-card {
background-color: greenyellow;
color: white;
transform: rotateY(180deg);
}
<div class="memory-game">
<div class="playing-cards">
<div class="front-card">A</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">B</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">a</div>
<div class="back-card"></div>
</div>
<div class="playing-cards">
<div class="front-card">b</div>
<div class="back-card"></div>
</div>
</div>
Edit: Added cursor effect

Using jquery connections but it isn't connecting div's together?

I am trying to create this page where I have different div and buttons that are scattered on the page and connecting them using jquery connections by musclesoft
I have tried this code but it seems that the connection isn't happening at all, I can't figure out what the issue is?
button {
min-width: 120px;
height: 120px;
background: #f56c29;
border-radius: 60px;
}
connection {
border: 30px solid #b51c29;
border-radius: 50px;
}
button.about {
position: absolute;
transition: .5s ease;
top: 50%;
left: 50%;
}
<!DOCTYPE html>
<html lang="en" >
<!-- Include jQuery and the Connections plugin -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="jquery.connections.js"></script>
<!-- Connect your elements like in this example -->
<script>
jQuery(document).ready(function() {
$('div').connections();
});
</script>
<head>
<meta charset="UTF-8">
<title>CodePen - A Pen by rasbsal</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div>
<button>
Text
</button>
</div>
<div>
<button class="about">
About
</button>
</div>
</body>
</html>
The connections are not visible because there's actually no space between the div elements (go to Inspect Element in Dev Tools and see for yourself highlighting the two DIV elements).
Use button as your connecting selector
jQuery(($) => {
$('button').connections();
});
button {
min-width: 120px;
height: 120px;
background: #f56c29;
border-radius: 60px;
}
connection {
border: 30px solid #b51c29;
border-radius: 50px;
}
button.about {
position: absolute;
transition: .5s ease;
top: 50%;
left: 50%;
}
<div>
<button>Text</button>
</div>
<div>
<button class="about">About</button>
</div>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/musclesoft/jquery-connections#1.0.1/jquery.connections.js"></script>

Click to hide and show the division

I have a sticky Ads at the footer with a HIDE button, I want when I click HIDE .stickyads content should be hidden by sliding down, but HIDE but should be appearing so as when I clcik again, the .stickyads content should appear by sliding up.
CSS:
#media (max-width: 800px) {
.stickyads {
position: fixed;
bottom: 0px;
left: 0;
}
.stickyadsHide {
width: 30px;
height: 30px;
display: flex;
position: absolute;
right: 0px;
top: -30px;
}
.stickyads .stickyadsContent {
overflow: hidden;
display: block;
position: relative;
width: 100%;
}
}
HTML Part:
<div class='stickyads'>
<div class='stickyadsHide' >
<span>HIDE</span>
</div>
<div class='stickyadsContent'>
Content Here...
</div>
</div>
button = document.querySelector('.stickyadsHide');
adCont = document.querySelector('.stickyadsContent');
hide = document.querySelector('.hide');
show = document.querySelector('.show');
button.addEventListener("click", () => {
adCont.classList.toggle('visbility');
hide.classList.toggle('visbility');
show.classList.toggle('visbility');
});
.stickyadsHide {
width: 50px;
height: 50px;
}
.btn {
position: absolute;
}
.stickyadsContent,
.btn {
opacity: 0;
transition: opacity 0.5s;
}
.visbility {
opacity: 1;
transition: opacity 0.5s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>document</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class='stickyads' id='removeads'>
<div class='stickyadsHide'>
<span class="btn hide visbility">HIDE</span>
<span class="btn show">SHOW</span>
</div>
<div class='stickyadsContent visbility'>
Content Here...
</div>
</div>
<script src="script.js"></script>
</body>
</html>
I think this is what you are looking for. slideToggle
HTML
<div class='stickyads'>
<div class='stickyadsHide' >
<span>HIDE</span>
</div>
<div class='stickyadsContent'>
Content Here...
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
CSS
.stickyads {
position: fixed;
bottom: 0px;
left: 0;
}
.stickyadsHide {
width: 30px;
height: 30px;
}
.stickyads .stickyadsContent {
overflow: hidden;
display: block;
position: relative;
width: 100%;
}
jQuery
$('.stickyadsHide').click(function() {
$('.stickyadsContent').slideToggle();
});
Check this link

How can I flip DIVs on click, with interaction between each other (one flips open, the other closes)?

I'm new to web development and I challenged myself with this task to master JavaScript. My task is to make different divs on the page flippable on click and interact with each other based on the current status.
I would like to learn two more things:
shorten/simplify the current JS code (if possible)
Have the divs interact with each other: when 'on click' the current one opens, but if any other of them was already open, it'll close. So only one div stay open at a time.
My current code (codepen: https://codepen.io/Loomeus/pen/RwKELbx):
HTML
var card = document.querySelector('.card');
card.addEventListener( 'click', function() {
card.classList.toggle('is-flipped');
});
var card2 = document.querySelector('.card2');
card2.addEventListener( 'click', function() {
card2.classList.toggle('is-flipped');
});
var card3 = document.querySelector('.card3');
card3.addEventListener( 'click', function() {
card3.classList.toggle('is-flipped');
});
#media screen and (min-width:650px){
.flipping {display: flex;
justify-content:space-between;
}
}
.scene, .scene2, .scene3 {
width: 200px;
height: 200px;
perspective: 1200px;
margin-left: auto;
margin-right: auto;
}
.card, .card2, .card3 {
width: 200px;
height: 200px;
position: relative;
transition: transform 1.5s;
transform-style: preserve-3d;
}
.card__face, .card__face2, .card__face3 {
position: absolute;
width: 200px;
height: 200px;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.card__face--front, .card__face--front2, .card__face--front3 {
background: red;
}
.card__face--back, .card__face--back2, .card__face--back3 {
background: blue;
transform: rotateY( 180deg );
}
.card.is-flipped, .card2.is-flipped, .card3.is-flipped {
transform: rotateY(180deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script defer src="/script.js"></script>
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<section class="flipping">
<div class="scene">
<div class="card">
<div class="card__face card__face--front">Front of first div</div>
<div class="card__face card__face--back">Back of first div</div>
</div>
</div>
<br>
<div class="scene2">
<div class="card2">
<div class="card__face2 card__face--front2">Front of second div</div>
<div class="card__face2 card__face--back2">Back of second div</div>
</div>
</div>
<br>
<div class="scene3">
<div class="card3">
<div class="card__face3 card__face--front3">Front of last div</div>
<div class="card__face3 card__face--back3">Back of last div</div>
</div>
</div>
</section
</body>
</html>
Would you be able to help me out?
Thanks!
You could simplify your code by using a common card class on all your cards. Then, you would need to remove the is-flipped class from all cards before flipping the clicked one:
var cards = document.querySelectorAll('.card');
cards.forEach(function (card) {
card.addEventListener('click', function () {
// Remove the class on all, toggle the clicked one
cards.forEach(function (c) {
if (c !== card) c.classList.remove('is-flipped');
else c.classList.toggle('is-flipped');
});
});
});
Fixed CodePen
Stack Snippet:
var cards = document.querySelectorAll('.card');
cards.forEach(function (card) {
card.addEventListener('click', function () {
// Remove the class on all, except the clicked one
cards.forEach(function (c) {
if (c !== card) c.classList.remove('is-flipped');
else c.classList.toggle('is-flipped');
});
});
});
#media screen and (min-width:400px){
.flipping {display: flex;
justify-content:space-between;
}
}
.scene, .scene2, .scene3 {
width: 100px;
height: 100px;
perspective: 1200px;
margin-left: auto;
margin-right: auto;
}
.card {
width: 100px;
height: 100px;
position: relative;
transition: transform 1.5s;
transform-style: preserve-3d;
}
.card__face, .card__face2, .card__face3 {
position: absolute;
width: 100px;
height: 100px;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.card__face--front, .card__face--front2, .card__face--front3 {
background: red;
}
.card__face--back, .card__face--back2, .card__face--back3 {
background: blue;
transform: rotateY( 180deg );
}
.card.is-flipped, .card2.is-flipped, .card3.is-flipped {
transform: rotateY(180deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script defer src="/script.js"></script>
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<section class="flipping">
<div class="scene">
<div class="card">
<div class="card__face card__face--front">Front of first div</div>
<div class="card__face card__face--back">Back of first div</div>
</div>
</div>
<br>
<div class="scene2">
<div class="card">
<div class="card__face2 card__face--front2">Front of second div</div>
<div class="card__face2 card__face--back2">Back of second div</div>
</div>
</div>
<br>
<div class="scene3">
<div class="card">
<div class="card__face3 card__face--front3">Front of last div</div>
<div class="card__face3 card__face--back3">Back of last div</div>
</div>
</div>
</section
</body>
</html>

Categories

Resources