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

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

Related

Click event only works once in querySelectorAll - 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

onclick from two elements not working with toggle properly

I want the div tag with id="hidden-gift-order" to be hidden when I click on the input and the div with class="checkmark". When I click on the input it works but the div tag when clicked on doesn't work. Can someone explain why so?
function Toggle_Visibility(p1) {
document.getElementById(p1).classList.toggle("d-none");
}
<!-- Bootstrap-4 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<!-- Body -->
<div class="form-field col-lg-12 mb-6">
<label class="checkbox-container ps-4 cursor-pointer" id="orderasgift">
<input id="giftbox" onclick="Toggle_Visibility('hidden-gift-order')" class="gift-order-checkbox" type="checkbox">
<div class="checkmark" onclick="Toggle_Visibility('hidden-gift-order')"></div>
</label>
</div>
<div class="d-none" id="hidden-gift-order">...</div>
UPDATE:
So, the div tag is a custom checkbox and I wanted to use that instead of the default one given to us. When I click on input and div inside the label, I want it to trigger Toggle_Visibility() and toggle the d-none class of the div#hidden-gift-order.
I am adding the CSS part of the code too!
PS: The Code snippet is not working so don't mind that, thanks!
CSS:
/* Hide the browser's default checkbox */
.checkbox-container .gift-order-checkbox {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
/* Create a custom checkbox */
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
background-color: var(--bs-white);
border: solid var(--bs-primary);
}
/* On mouse-over, add a grey background color */
.checkbox-container:hover input ~ .checkmark {
background-color: var(--bs-light);
}
/* When the checkbox is checked, add a blue background */
.checkbox-container input:checked ~ .checkmark {
background-color: var(--bs-white);
}
/* Create the checkmark/indicator (hidden when not checked) */
.checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the checkmark when checked */
.checkbox-container input:checked ~ .checkmark:after {
display: block;
}
/* Style the checkmark/indicator */
.checkbox-container .checkmark:after {
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid var(--bs-primary);
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
color: var(--bs-primary);
}
try to dont put input and div in label because when you click div the input is clicked too , i try this and its works :
<!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>
<script defer>
function Toggle_Visibility(p1) {
document.getElementById(p1).classList.toggle("d-none");
}
</script>
</head>
<body>
<div class="form-field col-lg-12 mb-6">
<input
id="giftbox"
onclick="Toggle_Visibility('hidden-gift-order')"
class="gift-order-checkbox"
type="checkbox"
/>
<div
class="checkmark"
onclick="Toggle_Visibility('hidden-gift-order')"
>sdf
</div>
</div>
<div class="d-none" id="hidden-gift-order">...</div>
</body>
</html>

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>

Slick - Code execution

I use the slick framework that allows me to have a carousel.
The problem is that on the second page of my carousel there is a css effect that starts. (code below)
The problem is that the css effect starts when the site is opened. So when I scroll the
caroussel the effect is already "past". I want the effect to start after clicking on one of the two
arrows (right and left).
I import the slick framework through url and saw that the button code is on
one of the url so I modify myself the button in my code (javascript).
After doing that nothing happens.
I do not understand !
Looking forward to an answer from you for my two problems.
Cordially.
/*(function() {
var slideContainer = $('.slide-container');
slideContainer.slick({
//id added to execute the function below
//https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js
//In this url you can see that prevArrow and nextArrow are the buttons
prevArrow: '<button id="prev" type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button">Previous</button>',
nextArrow: '<button id="nex" type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button">Next</button>',
});
$("#prev, #nex").click(function() {
$(".expand").addClass("myeffect2");
});
*/
$(".slide-container").slick({
});
body {
background-color: black;
color: #9E9E9E;
}
.slide-container {
margin: auto;
width: 600px;
text-align: center;
}
.wrapper {
padding-top: 100px;
padding-bottom: 40px;
}
.wrapper:focus {
outline: 0;
}
.card {
background: white;
width: 300px;
display: inline-block;
margin: auto;
border-radius: 19px;
position: relative;
text-align: center;
-webkit-box-shadow: -1px 15px 30px -12px black;
box-shadow: -1px 15px 30px -12px black;
}
/***** Effect *****/
.expand-bg {
background: none repeat scroll 0 0 #e6e6e6;
border-radius:16px;
height: 16px;
margin-bottom: 5px;
}
.expand {
border-radius: 13px;
height: 12px;
margin: 2px;
position: absolute;
}
.myeffect2 {
width:90%;
background:#000000;
-moz-animation:myeffect 8s ease-out;
-webkit-animation:myeffect 8s ease-out;
}
#-moz-keyframes myeffect2 {
0% {
width:0px;
}
100% {
width:90%;
}
}
#-webkit-keyframes myeffect {
0% {
width:0px;
}
100% {
width:90%;
}
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Test</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel='stylesheet prefetch' href='https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css'>
<link rel='stylesheet prefetch' href='https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick-theme.css'>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="slide-container">
<!--page1-->
<div class="wrapper">
<div class="card profile">
<div class="card__level card__level--profile">
<p>My name</p>
</div>
</div>
</div>
<!--end page1-->
<!--page2-->
<div class="wrapper">
<div class="card skills">
<div class="card__unit-name"</div>
</br>
<h3>My effect</h3>
<div class="expand-bg"> <div class="expand myeffect2"> </div> </div>
</div>
</div>
<!--end page2-->
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js'></script>
<script src="js/index.js"></script>
</body>
</html>
Scope the myeffect2 class or any class with an animation that you don't want to run unless the slide is active to the slick-active class.
Slick adds the "slick-active" class to slides that are in view.
.slick-active .myeffect2 {
width:90%;
background:#000000;
-moz-animation:myeffect 8s ease-out;
-webkit-animation:myeffect 8s ease-out;
}

How to prevent overlapping two bootstrap styled divs which can re-size and drag?

I created two divs which can drag and re-size. I used bootstrap to style these two divs. The code is fine and I can drag and re-size two divs finely. But these two divs are overlapping. What is the thing that I do incorrectly? Here is my code.
$('.draggable-handler').mousedown(function(e){
drag = $(this).closest('.draggable')
drag.addClass('dragging')
drag.css('left', e.clientX-$(this).width()/2)
drag.css('top', e.clientY-$(this).height()/2 - 10)
$(this).on('mousemove', function(e){
drag.css('left', e.clientX-$(this).width()/2)
drag.css('top', e.clientY-$(this).height()/2 - 10)
window.getSelection().removeAllRanges()
})
})
$('.draggable-handler').mouseleave(stopDragging)
$('.draggable-handler').mouseup(stopDragging)
function stopDragging(){
drag = $(this).closest('.draggable')
drag.removeClass('dragging')
$(this).off('mousemove')
}
#media (min-width: 600px) and ( min-height: 600px) {
.panel{
background-size: cover;
max-width: 1000px;
margin-left: 10px;
margin-right: 10px;
margin-top: 10px;
max-height: 1000px;
cursor: move;
resize: both;
background-color: #E6E6FA;
}
.panel-body{
background-color: #E6E6FA;
background-size: cover;
}
}
.resizable{
overflow: hidden;
resize:both;
background-size: cover;
}
.draggable{
position: absolute;
z-index: 100;
}
.draggable-handler{
cursor: pointer;
}
.dragging{
cursor: move;
z-index: 200 !important;
}
<!DOCTYPE html>
<meta charset="utf-8">
<html lang="en">
<head>
<title>Replayable widget</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</head>
<body>
<div id="div1_panel" class="panel panel-primary resizable draggable" >
<div class="panel-heading draggable-handler">
<h3 class="panel-title"><b>Div1</b></h3>
</div>
<div class="panel-body">
<b>Hi, I'm div1</b>
</div>
</div>
<div id="div2_panel" class="panel panel-primary resizable draggable" >
<div class="panel-heading draggable-handler">
<h3 class="panel-title"><b>Div2</b></h3>
</div>
<div class="panel-body">
<B>Hi, I'm div2</B>
</div>
</div>
</body>
</html>
Thank you...
You set both divs position:absolute in the class .draggable. That's why both divs are at the left-top corner (left: 0px, top: 0px). A solution would be to add the style position: absolute; not before the dragging starts, i.e. at the mousedown event.
e.g.:
https://jsfiddle.net/m3rg34qm/
All I have done in the fiddle is
removed position: absolute from the .draggable class
added drag.css('position', 'absolute'); inside of the onmousedown handler
assigned a static width to the container .panel

Categories

Resources