Clicking card in memory game doesn't flip it over - javascript

I'm trying to make a memory game and am struggling to get the cards to flip over when they're clicked. I expected the following for loop to call the function displayCard when a card (corresponding to each li item with class card) is clicked, which function toggles the classes show and open (sets the card to visible [displays icon] and changes the background color). Any suggestions?
CodePen
For loop:
for (let i = 0; i < cards.length; i++) {
card = cards[i];
card.addEventListener('click', displayCard);
card.addEventListener('click', cardOpen);
card.addEventListener('click', congratulations);
}
displayCard function:
let displayCard = function() {
this.classList.toggle('open');
this.classList.toggle('show');
this.classList.toggle('disabled');
};
CSS for classes show and open:
.card-deck .card.open {
/* transform: rotateY(0); */
background: #02b3e4;
cursor: default;
animation-name: flipInY;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
animation-duration: .75s;
}
.card-deck .card.show {
font-size: 33px;
}
.show {
visibility: visible !important;
opacity: 100 !important;
}

There are two errors in your code that need to be fixed and then the flipping occurs :
in the startGame function, deck.appendChild is not a function. deck was initialized with document.getElementsByClassName('card-deck'). And document.getElementsByClassName returns an array. You need to select the first index of this array.
in the startGame function, interval is not defined. Your function is called before the interval variable is declared. Either move up the interval variable declaration of declare it with the var keyword to "reserve" the identifier.
let card = document.getElementsByClassName('card');
// Spread operator (new in ES6) allows iterable to expand where 0+ arguments are expected
let cards = [...card];
let deck = document.getElementsByClassName('card-deck')[0];
let moves = 0;
let counter = document.querySelector('.moves');
let stars = document.querySelectorAll('.fa-star');
let matchingCard = document.getElementsByClassName('matching');
let starsList = document.querySelectorAll('.stars li');
let closeIcon = document.querySelector('.close');
let modal = document.getElementsByClassName('main-modal');
let openedCards = [];
// Game timer
let second = 0, minute = 0, hour = 0;
let timer = document.querySelector('.timer');
let interval;
// Shuffle function from http://stackoverflow.com/a/2450976
function shuffle(array) {
let currentIndex = array.length, temporaryValue, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
// Shuffles cards upon page load
document.body.onload = startGame();
function startGame() {
// Shuffles deck
cards = shuffle(cards);
// Removes any existing classes from each card
for (let i = 0; i < cards.length; i++) {
deck.innerHTML = '';
[].forEach.call(cards, function(item) {
deck.appendChild(item);
});
cards[i].classList.remove('show', 'open', 'matching', 'disabled');
}
// Resets number of moves
moves = 0;
counter.innerHTML = moves;
// Resets star rating
for (let i = 0; i < stars.length; i++) {
stars[i].style.color = '#ffd700';
stars[i].style.visibility = 'visible';
}
// Resets timer
let second = 0;
let minute = 0;
let hour = 0;
let timer = document.querySelector('.timer');
timer.innerHTML = '0 mins 0 secs';
if (typeof interval != "undefined") {
sclearInterval(interval);
}
}
// Toggles open and show classes to display cards
let displayCard = function() {
this.classList.toggle('open');
this.classList.toggle('show');
this.classList.toggle('disabled');
};
// Adds opened cards to openedCards list and checks if cards are a match or not
function cardOpen() {
openedCards.push(this);
let len = openedCards.length;
if (len === 2) {
moveCounter();
if (openedCards[0].type === openedCards[1].type) {
matching();
} else {
notMatching();
}
}
}
// When cards match
function matching() {
openedCards[0].classList.add('matching', 'disabled');
openedCards[1].classList.add('matching', 'disabled');
openedCards[0].classList.remove('show', 'open');
openedCards[1].classList.remove('show', 'open');
openedCards = [];
}
// When cards don't match
function notMatching() {
openedCards[0].classList.add('not-matching');
openedCards[1].classList.add('not-matching');
disable();
setTimeout(function() {
openedCards[0].classList.remove('show', 'open', 'not-matching');
openedCards[1].classList.remove('show', 'open', 'not-matching');
enable();
openedCards = [];
}, 1100);
}
// Disables cards temporarily
function disable() {
Array.prototype.filter.call(cards, function(card) {
card.classList.add('disabled');
});
}
// Enables cards, disables matching cards
function enable() {
Array.prototype.filter.call(cards, function(card) {
card.classList.remove('disabled');
for (let i = 0; i < matchingCard.length; i++) {
matchingCard[i].classList.add('disabled');
}
});
}
// Counts player's moves
function moveCounter() {
moves++;
counter.innerHTML = moves;
// Starts timer on first click
if (moves == 1) {
second = 0;
minute = 0;
hour = 0;
startTimer();
}
// Sets star rating based on number of moves
if (moves > 8 && moves < 12) {
for (i = 0; i < 3; i++) {
if (i > 1) {
stars[i].style.visibility = 'collapse';
}
}
}
else if (moves > 13) {
for (i = 0; i < 3; i++) {
if (i > 0) {
stars[i].style.visibility = 'collapse';
}
}
}
}
function startTimer() {
interval = setInterval(function() {
timer.innerHTML = minute + 'mins ' + second + 'secs';
second++;
if (second == 60) {
minute++;
second = 0;
}
if (minute == 60) {
hour++;
minute = 0;
}
}, 1000);
}
// Congratulates player when all cards match and shows modal, moves, time and rating
function congratulations() {
if (matchingCard.length == 16) {
clearInterval(interval);
let finalTime = timer.innerHTML;
// Shows congratulations modal
modal.classList.add('show');
let starRating = document.querySelector('.stars').innerHTML;
// Shows move, time, and rating on modal
document.getElementsByClassName('final-move').innerHTML = moves;
document.getElementsByClassName('star-rating').innerHTML = starRating;
document.getElementsByClassName('total-time').innerHTML = finalTime;
closeModal();
}
}
// Closes modal upon clicking its close icon
function closeModal() {
closeIcon.addEventListener('click', function(e) {
modal.classList.remove('show');
startGame();
});
}
function reset() {
modal.classList.remove('show');
startGame();
}
// Adds event listeners to each card
for (let i = 0; i < cards.length; i++) {
card = cards[i];
card.addEventListener('click', displayCard);
card.addEventListener('click', cardOpen);
card.addEventListener('click', congratulations);
}
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #ffffff;
font-family: 'Permanent Marker', cursive;
font-size: 16px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h1 {
font-family: 'Gloria Hallelujah', cursive;
}
/* DECK OF CARDS */
.card-deck {
width: 85%;
background: #716F71;
padding: 1rem;
border-radius: 4px;
box-shadow: 8px 9px 26px 0 rgba(46, 61, 73, 0.5);
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
margin: 0 0 3em;
}
.card-deck .card {
height: 3.7rem;
width: 3.7rem;
margin: 0.2rem 0.2rem;
background: #141214;;
font-size: 0;
color: #ffffff;
border-radius: 5px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5);
}
.card-deck .card.open {
/* transform: rotateY(0); */
background: #02b3e4;
cursor: default;
animation-name: flipInY;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
animation-duration: .75s;
}
.card-deck .card.show {
font-size: 33px;
}
.show {
visibility: visible !important;
opacity: 100 !important;
}
.card-deck .card.matching {
cursor: default;
background: #E5F720;
font-size: 33px;
animation-name: rubberBand;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
animation-duration: .75s;
}
.card-deck .card.not-matching {
animation-name: pulse;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
animation-duration: .75s;
background: #e2043b;
}
.card-deck .card.disabled {
pointer-events: none;
opacity: 0.9;
}
/* SCORE PANEL */
.score-panel {
text-align: left;
margin-bottom: 10px;
}
.score-panel .stars {
margin: 0;
padding: 0;
display: inline-block;
margin: 0 5px 0 0;
}
.score-panel .stars li {
list-style: none;
display: inline-block;
}
.score-panel .restart {
float: right;
cursor: pointer;
}
.fa-star {
color: #FFD700;
}
.timer {
display: inline-block;
margin: 0 1rem;
}
/* CONGRATULATIONS MODAL */
.overlay {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.7);
transition: opacity 500ms;
visibility: hidden;
opacity: 0;
}
.overlay:target {
visibility: visible;
opacity: 1;
}
.popup {
margin: 70px auto;
padding: 20px;
background: #ffffff;
border-radius: 5px;
width: 85%;
position: relative;
transition: all 5s ease-in-out;
font-family: 'Gloria Hallelujah', cursive;
}
.popup h2 {
margin-top: 0;
color: #333;
font-family: Tahoma, Arial, sans-serif;
}
.popup .close {
position: absolute;
top: 20px;
right: 30px;
transition: all 200ms;
font-size: 30px;
font-weight: bold;
text-decoration: none;
color: #333;
}
.popup .close:hover {
color: #e5f720;
}
.popup .congrats-message,
.info-message {
max-height: 30%;
overflow: auto;
text-align: center;
}
.star-rating li {
display: inline-block;
}
.play-again {
background-color: #141214;
padding: 0.7rem 1rem;
font-size: 1.1rem;
display: block;
margin: 0 auto;
width: 50%;
font-family: 'Gloria Hallelujah', cursive;
color: #ffffff;
border-radius: 5px;
}
/* Animations */
#keyframes flipInY {
from {
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
animation-timing-function: ease-in;
opacity: 0;
}
40% {
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
animation-timing-function: ease-in;
}
60% {
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
opacity: 1;
}
80% {
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
}
to {
transform: perspective(400px);
}
}
#keyframes rubberBand {
from {
transform: scale3d(1, 1, 1);
}
30% {
transform: scale3d(1.25, 0.75, 1);
}
40% {
transform: scale3d(0.75, 1.25, 1);
}
50% {
transform: scale3d(1.15, 0.85, 1);
}
65% {
transform: scale3d(.95, 1.05, 1);
}
75% {
transform: scale3d(1.05, .95, 1);
}
to {
transform: scale3d(1, 1, 1);
}
}
#keyframes pulse {
from {
transform: scale3d(1, 1, 1);
}
50% {
transform: scale3d(1.2, 1.2, 1.2);
}
to {
transform: scale3d(1, 1, 1);
}
}
/* MEDIA QUERIES */
#media (max-width: 320px) {
.card-deck {
width: 85%;
}
.card-deck .card {
height: 4.7rem;
width: 4.7rem;
}
}
/* For tablets and larger screens */
#media (min-width: 768px) {
.container {
font-size: 22px;
}
.card-deck {
width: 660px;
height: 680px;
}
.card-deck .card {
height: 125px;
width: 125px;
}
.popup {
width: 60%;
}
}
<!-- <!doctype html> -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>Matching Game</title>
<meta name="description" content="">
<link rel="stylesheet prefetch" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
<link rel="stylesheet prefetch" href="https://fonts.googleapis.com/css?family=Coda">
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="container">
<header>
<h1>Matching Game</h1>
</header>
<section class="score-panel">
<ul class="stars">
<li><i class="fa fa-star"></i></li>
<li><i class="fa fa-star"></i></li>
<li><i class="fa fa-star"></i></li>
</ul>
<span class="moves">0</span> moves
<div class="timer"></div>
<div class="restart" onclick=startGame()>
<i class="fa fa-repeat"></i>
</div>
</section>
<ul class="card-deck">
<li class="card" type="diamond">
<i class="fa fa-diamond"></i>
</li>
<li class="card" type="plane">
<i class="fa fa-paper-plane-o"></i>
</li>
<li class="card matching" type="anchor">
<i class="fa fa-anchor"></i>
</li>
<li class="card" type="bolt" >
<i class="fa fa-bolt"></i>
</li>
<li class="card" type="cube">
<i class="fa fa-cube"></i>
</li>
<li class="card matching" type="anchor">
<i class="fa fa-anchor"></i>
</li>
<li class="card" type="leaf">
<i class="fa fa-leaf"></i>
</li>
<li class="card" type="bicycle">
<i class="fa fa-bicycle"></i>
</li>
<li class="card" type="diamond">
<i class="fa fa-diamond"></i>
</li>
<li class="card" type="bomb">
<i class="fa fa-bomb"></i>
</li>
<li class="card" type="leaf">
<i class="fa fa-leaf"></i>
</li>
<li class="card" type="bomb">
<i class="fa fa-bomb"></i>
</li>
<li class="card open show" type="bolt">
<i class="fa fa-bolt"></i>
</li>
<li class="card" type="bicycle">
<i class="fa fa-bicycle"></i>
</li>
<li class="card" type="plane">
<i class="fa fa-paper-plane-o"></i>
</li>
<li class="card" type="cube">
<i class="fa fa-cube"></i>
</li>
</ul>
<div class="main-modal overlay">
<div class="popup">
<h2>Congratulations!</h2>
<a class="close" href=# >×</a>
<div class="congrats-message">
Congratulations, you're a winner!
</div>
<div class="info-message">
<p>You made <span class=final-move></span> moves </p>
<p>In <span class=total-time></span></p>
<p>Rating: <span class=star-rating></span></p>
</div>
<button class="play-again" onclick="reset()">
Play again
</button>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>

Related

How to Detect mousewheel Movement and Make It not Incremental

May you all have a good day Today!
I finally made my scrollable tab, but it's not what I want. Because, when I scroll up one time it moves to the previous tab in which one scroll is one movement, it's incremental. But, what I want is as much I scroll the mouse once, it changes to another tab. I already add the console.log to my code below. My reference is Fullpage JS and this landing page. Please go see it if you don't understand my explanation.
UPDATE-1 :
I already found it in another post of stackoverflow that very similar to my problem in here : Detect the number of times mouse wheel was spun and not the length it was spun. But, alvaro commented that this method not working in kinetic devices.
Please help me to get through this. So, here's my code :
//Add & remove class tab, contents, & menu onclick & wheel
window.addEventListener('DOMContentLoaded', ()=> {
let tabs = document.querySelectorAll('.tab');
let content = document.querySelectorAll('.content');
let firstTab = function(tabs) {tabs.classList.add('tab-active')};
let firstContent = function(content) {content.classList.add('content-active')};
let activeTab = 0;
firstTab(tabs[0]);
firstContent(content[0]);
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', () => tabClick(i));
}
function detect(e) {
var delta = null,
direction = false;
if(!e) {e = window.event;}
if(e.wheelDelta) {delta = e.wheelDelta / 60;
} else if(e.detail) {delta = -e.detail / 2;}
if(delta !== null) {
direction = delta > 0 ? 'up' : 'down';}
return direction;
}
function handle(direction) { //mousewheel to change tabs
console.log(direction);
if(direction == 'down') {
if(activeTab >= tabs.length - 1) {
activeTab = 0;
tabClick(activeTab);
} else {
tabClick(activeTab + 1);
}
} else if(direction == 'up') {
if(activeTab === 0) {
activeTab = tabs.length - 1;
tabClick(activeTab);
} else {
tabClick(activeTab - 1);
}
} else {
// this means the direction of the mouse wheel could not be determined
}
}
document.onmousewheel = function(e) {handle(detect(e));};
if(window.addEventListener) {document.addEventListener
('DOMMouseScroll', function(e) {handle(detect(e));});
}
function tabClick(currentTab) {
removeActive();
//Add Active Class
tabs[currentTab].classList.add('tab-active');
content[currentTab].classList.add('content-active');
activeTab = currentTab;
}
function removeActive() {
for (let i = 0; i < tabs.length; i++) {
//Remove Active Class
content[i].classList.remove('content-active');
content[i].classList.add('content-show');
setTimeout(function() {
content[i].classList.remove('content-show');
},1500);
tabs[i].classList.remove('tab-active');
}
}
})
/* WHOLE CONTAINER */
.container {
width: 96vw;
height: 96vh;
}
/* TABS */
.tabs {
display: flex;
height: 50px;
overflow: hidden;
align-items: center;
justify-content: center;
width: 100%;
}
.tab {
font-size: 14px;
padding: 5px 10px;
cursor: pointer;
letter-spacing: 2px;
text-alignment: center;
}
#red.tab-active {background-color: rgb(245, 66, 66);}
#blue.tab-active {background-color: rgb(66, 135, 245);}
#yellow.tab-active {background-color: rgb(245, 215, 66);}
#green.tab-active {background-color: rgb(56, 235, 98);}
#cyan.tab-active {background-color: rgb(79, 247, 219);}
/* TAB CONTENTS */
.contents {
width: 100%;
margin-top: 5px;
height: 80%;
}
.content {
width: 96%;
height: 80%;
display: none;
padding: 0;
margin: 0;
border: none;
position: absolute;
}
.content-show {
display: flex;
animation-name: fade-out;
animation-duration: 2.5s;
}
#keyframes fade-out {
0% {
opacity: 1;
display: flex;
}
99% {
opacity: 0;
display: flex;
}
100% {
opacity: 0;
display: none;
}
}
.content-active {
display: flex;
border: none;
justify-content: center;
animation-name: fade-in;
animation-duration: 2.5s;
}
#keyframes fade-in {
0% {
display: none;
opacity: 0;
}
1% {
display: block;
opacity: 0.01;
}
100%{
display: block;
opacity: 1;
}
}
#red.content-active {background-color: rgb(245, 66, 66);}
#blue.content-active {background-color: rgb(66, 135, 245);}
#yellow.content-active {background-color: rgb(245, 215, 66);}
#green.content-active {background-color: rgb(56, 235, 98);}
#cyan.content-active {background-color: rgb(79, 247, 219);}
<div class="container">
<div class="tabs">
<div id="red" class="tab">RED</div>
<div id="blue" class="tab">BLUE</div>
<div id="yellow" class="tab">YELLOW</div>
<div id="green" class="tab">GREEN</div>
<div id="cyan" class="tab">CYAN</div>
</div>
<div class="contents">
<div id="red" class="content"></div>
<div id="blue" class="content"></div>
<div id="yellow" class="content"></div>
<div id="green" class="content"></div>
<div id="cyan" class="content"></div>
</div>
</div>
Thanks A lot Guys..

how to stop multiple notifications changing positions?

i have a small notifications problem, when i insert a element the position of first element is changing so i wanna make it when the element is inserted the first last notification still in same position until it delete itself
Video showing the problem
i call this function when i will insert a notification into phone
function createNotify(image, title, detail, time, color, iconColor) {
var random = Math.floor(Math.random() * 10000) + 1;
var htmlse = "";
htmlse +=
`<div id="${random}" style="background-color: ${color}"class="notification-container not-the-call">
<div class="app-bar">
<div class="icon" style="color: ${iconColor};">${image}</div>
<div class="name">
<p class="MuiTypography-root MuiTypography-body2 MuiTypography-colorTextPrimary"
style="word-break: break-word;">${title}</p>
</div>
<p class="MuiTypography-root MuiTypography-body2 MuiTypography-colorTextPrimary"
style="word-break: break-word;">${time}</p>
</div>
<div class="content">
<div class="text">
<p class="MuiTypography-root MuiTypography-body1 MuiTypography-colorTextPrimary"
style="word-break: break-word;">${detail}</p>
</div>
</div>
</div>`
$('.top-notifications-wrapper').append(htmlse)
$(function () {
$(".not-the-call").click(function() {
var removed = $(this)
for (i = 0; i < removed.length; i++) {
removed[i].style.animation = "cometopaparevers 0.5s";
setTimeout(function() {
for (i = 0; i < removed.length; i++) {
removed[i].innerHTML = "";
removed[i].remove();
}
}, 499)
}
});
})
setTimeout(function() {
var topNotifyReversVar = document.getElementById(random);
topNotifyReversVar.style.animation = "cometopaparevers 0.5s";
setTimeout(function() {
topNotifyReversVar.innerHTML = "";
topNotifyReversVar.remove();
}, 499)
}, 3300)
};
and this css
.top-notifications-wrapper {
width: 100%;
position: absolute;
left: 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
z-index: 200;
opacity: 1;
top: 24px;
}
.top-notifications-wrapper>.notification-container {
background-color: rgba(53, 49, 52, .95);
width: calc(100% - 32px);
height: 100%;
padding: 6px 8px;
border-radius: 8px;
color: #c8c6ca;
cursor: pointer;
margin-bottom: 4px;
opacity: 1;
-webkit-animation: cometopapa;
animation: cometopapa;
-webkit-animation-duration: .5s;
animation-duration: .5s;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
transform: translateY(0);
}
.top-notifications-wrapper-mounted {
pointer-events: all;
z-index: -1;
}
and this html
<div class="notify-wraper">
<div class="top-notifications-wrapper top-notifications-wrapper-mounted" style="max-height: 80px;"></div>
</div>

How to remove a css class and close a pop up message at the same time?

I'm modifying a memory game (originally in this repo) which shows a pop up message with the game results once the game is completed:
When the pop up message is introduced, the rest of the screen is assigned a "game-over" css class that darkens the screen (behind the pop up).
//function for what happens when all pairs are found and the game is over
function gameOver() {
stopWatch();
$('.container').addClass('animated rotateIn');
messageWinning();
}
//function for the popup message on winning
function messageWinning() {
$(`<section class="game-over"><div class="message-box" > <h2>Yay! You have found all pairs!</h2><p>Number of attempts: ${attempts}</p><p>Time required: ${showMinutes}:${showSeconds} </p><p>Level: ${stars} </p><p><i class="fas fa-undo"></i></p></section>`).insertAfter($('.game'));
$('.message-box').fadeIn(1);
}
How can I add some js that will let me to close the pop up message AND at the same time remove the "game-over" class, so the user can see their cards once they have completed the game?
What I've done so far but hasn't worked:
I added the following code to the js file to remove the "game-over" class but this never worked. I also tried it without the parent() variation but still no results.
$('.message-box').click(function(){
$(this).parent().removeClass('game-over');
});
Add this <div class="close-popup"> to inside message-box popup.
<div class="close-popup">Close</div>
Add below CSS to place the close top of the right side of the popup.
.message-box {
position: relative;
}
.close-popup {
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
}
On click of close hide .message-box and remove .game-over class from a parent.
$(document).on('click', '.close-popup', function() {
$('.message-box').hide().parent().removeClass('game-over');
createBoard();
});
Check below snippet
$(function() {
//DECLARATION OF VARIABLES
const memoryBoard = $('#memory-game');
//array that holds the values for the memory cards
let cardArray = ['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D', 'E', 'E', 'F', 'F', 'G', 'G', 'H', 'H'];
let comparisonArray = [];
//
let attempts = 0; //counts how many attempts a player has made
let stars = '<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i>'; //stores the stars to display
let clickCount = 0; //counts if this is the first click in an attempt
let pairs = 0; //counts how many pairs have already been discovered
let cardID = ''; //stores the card ID of solved pairs
let seconds = 00;
let tens = 00;
let minutes = 00;
let appendSeconds = $("#seconds");
let appendMinutes = $("#minutes");
let showSeconds = "00";
let showMinutes = "00";
let Interval;
//on page load
createBoard();
//EVENT TRIGGERS
//when clicking the undo icon reload the page
$(document).on('click', '.fa-undo', function() {
location.reload();
});
$('.card').click(function(event) {
//if this is the initial click, start the stopwatch
if (attempts === 0) {
startWatch();
};
//flip the card if it isn't already open or the comparison array full
if ($(this).hasClass("flipped") || $(this).hasClass("solved") || comparisonArray.length >= 2) {
return;
} else {
flipCard($(event.target).parent());
};
//open the card and store the card information in an array
comparisonArray.push($(this).data("card-type"));
//if this is the first card clicked simply count the click and number of attempts
if (clickCount === 0) {
clickCount++;
recordAttempts();
} else {
//if this is the second card clicked compare whether it is the same as the other stored card. If yes, add to the number of pairs and change the css attribute to permanently leave the card open.
if (comparisonArray[0] === comparisonArray[1]) {
$("[data-card-type=" + comparisonArray[0] + "]").removeClass('flipped').addClass('solved');
$("[data-card-type=" + comparisonArray[0] + "]").parent().addClass('animated pulse');
pairs++;
if (pairs === 8) {
gameOver();
}
};
//close all unsuccessfully opened cards and clear the comparison array with a short delay
setTimeout(function() {
flipCard($('.flipped'));
comparisonArray = [];
}, 1000);
//reset the click count
clickCount = 0;
}
});
//FUNCTIONS
//function to flip cards
function flipCard(element) {
$(element).toggleClass('flipped');
}
//function to record the number of attempts of a player and to reduce the number of stars based on performance
function recordAttempts() {
attempts++;
$('#attempts').html(attempts);
if (attempts > 16 && attempts < 24) {
stars = '<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else if (attempts >= 24 && attempts < 32) {
stars = '<i class="fas fa-star"></i><i class="far fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else if (attempts >= 32) {
stars = '<i class="far fa-star"></i><i class="far fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else {
return;
};
}
//function to create the memory board
function createBoard() {
cardArray = shuffle(cardArray);
memoryBoard.html('');
for (i = 1; i <= cardArray.length; i++) {
memoryBoard.append($(`<div class='container'><div class='card' data-card-type='${cardArray[i-1]}'><figure class='front'></figure><figure class='back'></figure></div></div>'`));
}
};
//function for what happens when all pairs are found and the game is over
function gameOver() {
stopWatch();
$('.container').addClass('animated infinite rotateIn');
messageWinning();
}
//function for the popup message on winning
function messageWinning() {
$(`<section class="game-over"><div class="message-box"><div class="close-popup">Close</div><h2>Yay! You have found all pairs!</h2><p>Number of attempts: ${attempts}</p><p>Time required: ${showMinutes}:${showSeconds} </p><p>Level: ${stars} </p><p><i class="fas fa-undo"></i></p></div></section>`).insertAfter($('.game'));
$('.message-box').fadeIn(1000);
}
// shuffle function from http://stackoverflow.com/a/2450976
function shuffle(array) {
var currentIndex = array.length,
temporaryValue, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//Stopwatch function, based on https://www.cssscript.com/a-minimal-pure-javascript-stopwatch/
function stopWatch() {
clearInterval(Interval);
}
function startWatch() {
clearInterval(Interval);
Interval = setInterval(startTimer, 10);
function startTimer() {
tens++;
if (tens > 99) {
seconds++;
showSeconds = "0" + seconds;
appendSeconds.html(showSeconds);
tens = 0;
}
if (seconds > 9) {
showSeconds = seconds;
appendSeconds.html(showSeconds);
}
if (seconds > 59) {
minutes++;
showMinutes = "0" + minutes;
appendMinutes.html(showMinutes);
seconds = 0;
showSeconds = "0" + 0;
appendSeconds.html(showSeconds);
}
if (minutes > 9) {
showMinutes = minutes;
appendMinutes.html(showMinutes);
}
}
}
$(document).on('click', '.close-popup', function() {
$('.message-box').hide().parent().removeClass('game-over');
createBoard();
});
});
/* ...............................
GLOBAL SETTINGS
.................................*/
/* COLOR PALETTE
credit to http://colorpalettes.net/color-palette-1298/
#a6d5e5
#85c3b4
#fbed60
#96bce9
#ddcfe8
*/
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
body,
html {
background: #fff;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
color: #555;
font-size: 16px;
overflow-x: hidden;
text-align: center;
background: #ffffff;
}
h1 {
font-family: 'Amatic SC', cursive;
font-size: 300%;
padding: 20px;
}
h2 {
margin: 5% 0;
color: #000000;
font-weight: 300;
}
.fa-star {
color: #fbed60;
}
p {
margin: 1%;
}
a {
text-decoration: none;
color: #000;
}
.fa-undo {
padding: 0 20% 20% 20%;
}
.message-box .fa-undo {
padding: 10%;
}
.fa-undo:hover {
cursor: pointer;
}
/* ...............................
GENERAL PAGE LAYOUT
.................................*/
header::before,
footer::after {
display: block;
content: '';
width: 100%;
background: #fbed60;
height: 20px;
}
header {
margin: auto;
background: #ffff92;
-webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
}
footer {
margin: 20px 0 0 0;
background: #f5f5f5;
}
footer div {
font-size: 80%;
padding: 10px;
}
/* ...............................
SPECIFIC SETTINGS
.................................*/
.game {
max-width: 550px;
margin: auto;
}
/* STATISTICS */
.stats {
margin: 30px 0 10px 0;
}
ul.stats {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
}
ul.stats li {
display: inline-block;
padding: 5px;
width: 25%;
}
/* CARDBOARD */
/* card with equal height and width on resizing , credit to http://www.mademyday.de/css-height-equals-width-with-pure-css.html/ */
.container {
display: inline-block;
width: 23%;
margin: 1%;
position: relative;
-webkit-perspective: 800px;
perspective: 800px;
}
.container::before {
content: "";
display: block;
padding-top: 100%;
}
/*card flip effect, credit to https://desandro.github.io/3dtransforms/docs/card-flip.html */
.card {
width: 100%;
height: 100%;
position: absolute;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transition: -webkit-transform 0.3s;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.card figure {
margin: 0;
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
border-radius: 10px 5px;
-webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
}
.card figure:hover {
-webkit-box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.front {
background-color: #85c3b4;
}
.back {
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
}
.card.flipped,
.card.solved {
-webkit-transform: rotateY( 180deg);
transform: rotateY( 180deg);
}
/* Card Backgrounds */
[data-card-type="A"] .back {
background: #f5f5f5 url('https://via.placeholder.com/150.jpg');
}
[data-card-type="B"] .back {
background: #f5f5f5 url('https://via.placeholder.com/151.jpg');
}
[data-card-type="C"] .back {
background: #f5f5f5 url('https://via.placeholder.com/152.jpg');
}
[data-card-type="D"] .back {
background: #f5f5f5 url('https://via.placeholder.com/153.jpg');
}
[data-card-type="E"] .back {
background: #f5f5f5 url('https://via.placeholder.com/154.jpg');
}
[data-card-type="F"] .back {
background: #f5f5f5 url('https://via.placeholder.com/155.jpg');
}
[data-card-type="G"] .back {
background: #f5f5f5 url('https://via.placeholder.com/156.jpg');
}
[data-card-type="H"] .back {
background: #f5f5f5 url('https://via.placeholder.com/157.jpg');
}
/* POPUP MESSAGE ON WINNING */
.game-over {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
z-index: 2;
}
.message-box {
background: rgb(255, 255, 255);
width: 70%;
max-width: 500px;
max-height: 500px;
display: -webkit-box;
display: -ms-flexbox;
display: none;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-flow: column;
flex-flow: column;
padding: 5%;
border: 5px solid #fbed60;
border-radius: 20px;
}
.message-box {
position: relative;
}
.close-popup {
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Memory Card Game</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.9/css/all.css">
<link href="https://fonts.googleapis.com/css?family=Amatic+SC|Open+Sans:300" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css#3.5.2/animate.min.css">
</head>
<body>
<header>
<h1>Memory Card Game</h1>
</header>
<main>
<section class="game">
<ul class="stats">
<li id="stars"><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i></li>
<li>
<p>Attempts</p>
<p id="attempts">0</p>
</li>
<li><i class="fas fa-hourglass-start"></i>
<p><span id="minutes">00</span>:<span id="seconds">00</span></p>
</li>
<li><i class="fas fa-undo"></i></li>
</ul>
<div id="memory-game">
</div>
</section>
</main>
<footer>
<div>Icons made by Smashicons from www.flaticon.com are licensed by <a href="http://creativecommons.org/licenses/by/3.0/"
title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
</footer>
</body>
</html>

Two identical modals, but one does not work. Why?

EDIT:
The new code:
const modal2 = () => {
'use strict';
class Modal {
constructor() {
this.triggers = document.querySelectorAll('.js-modal2');
this.close = document.querySelectorAll('.js-close-modal');
this.modals = document.querySelectorAll('.modal');
this.modalInners = document.querySelectorAll('.modal-inner');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal.hideModal, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body')) {
Modal.hideModal();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal.hideModal();
}
}
static hideModal() {
let modalOpen = document.querySelector('.modal.modal-visible');
modalOpen.querySelector('.modal-inner').classList.remove('modal-reveal');
document.querySelector('.modal-body').addEventListener('transitionend', Modal.modalBody, false);
document.body.classList.add('modal-fadeOut');
}
closeModal(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal-reveal')) {
document.querySelector('.modal.modal-visible').classList.remove('modal-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modalID = el.currentTarget.dataset.modal2;
let modal2 = document.getElementById(modalID);
document.body.classList.add('modal-body');
modal.classList.add('modal-visible');
}
revealModal(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal-visible')) {
el.target.querySelector('.modal-inner').classList.add('modal-reveal');
}
}
static modalBody(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal') && !el.target.classList.contains('modal-visible')) {
document.body.classList.remove('modal-body', 'modal-fadeOut');
}
}}
new Modal();
};
export default modal2;
I am sorry if this is going to be a bit long.
I have two ul elements on my page that contain a list that is made to look like a subway map.
For the first ul, I made a class inside the li elements, which fetch json data that pops up in a modal.
This modal WORKS!
The problem is my SECOND modal.
Here I have a simple button, and when I click that button I want a modal to pop up, containing my second ul element.
The problem is that I can´t get THIS modal to work.
I renamed everything, both in the html, css and script, and I am going crazy because I can´t find the error. I need this project finished tonight, so I am getting more and more frustrated about it
My test page is here: http://handig.dk/EXAM2019/index.html
The second section contains my working modal.
The third contains the non-working modal.
The html
`<div class="map">
<ul>
<li id="getTime" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime2" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime3" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime4" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime5" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime6" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime7" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime8" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime9" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime10" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime11" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime12" class="js-modal" data-modal="modal-1">Text</li>
</ul>
<h2>Text</h2>
<div id="modal-1" class="modal">
<div class="modal-inner">
<div id="modal-body">
</div>
<a class="js-close-modal">×</a>
<div class="modal-content">
<p class="modal-headline">Text</p>
</div>
</div><!-- .modal-content -->
</div><!-- .modal-inner -->
</div><!-- .modal -->
<!-- SECOND MODAL (NOT WORKING) -->
<div class="trains">
<button class="js-modal2" data-modal="modal-2">Tjek driften</button>
<div id="modal-2" class="modal2">
<div class="modal-inner2">
<div id="modal-body2">
</div>
<a class="js-close-modal2">×</a>
<div class="modal-content2">
<p class="modal-headline">Drift</p>
<ul>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
</ul>
</div>
</div><!-- .modal-content2 -->
</div><!-- .modal-inner2 -->`
CSS for the WORKING modal
.modal-body {
overflow: hidden;
position: relative;
}
#modal-body {
background:#900;
}
.modal-body:before {
position: fixed;
display: block;
content: '';
top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.75);
z-index: 10;
}
.modal-body:before {
-webkit-animation: fadeIn 320ms ease;
animation: fadeIn 320ms ease;
transition: opacity ease 320ms;
}
.modal-body.modal-fadeOut:before {
opacity: 0;
}
.modal {
transition: all ease 0.01s;
display: block;
opacity: 0;
height: 0;
position: fixed;
content: '';
top: 0;
left: 0;
right: 0;
z-index: 2000;
text-align: center;
overflow: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modal.modal-visible {
opacity: 1;
height: auto;
bottom: 0;
}
.modal-inner {
transition: all ease 320ms;
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
position: relative;
display: inline-block;
background-color: #fff;
width: 90%;
max-width: 600px;
background: #fff;
opacity: 0;
margin: 40px 0;
border-radius: 4px;
box-shadow: 0 30px 18px -20px #020202;
}
.modal-inner.modal-reveal {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
.js-close-modal {
transition: color 320ms ease;
color: #9e9e9e;
opacity: 0.75;
position: absolute;
z-index: 2;
right: 0px;
top: 0px;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 20px;
cursor: pointer;
text-align: center;
}
.js-close-modal:hover {
color: #000;
}
.modal-headline {
font-size: 1.5em;
font-weight: 700;
}
.modal-content {
letter-spacing: 1px;
}
.modal-content2 {
letter-spacing: 1px;
}
CSS for modal that does NOT work
.modal-body2 {
overflow: hidden;
position: relative;
}
#modal-body2 {
background:#900;
}
.modal-body2:before {
position: fixed;
display: block;
content: '';
top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.75);
z-index: 10;
}
.modal-body2:before {
-webkit-animation: fadeIn 320ms ease;
animation: fadeIn 320ms ease;
transition: opacity ease 320ms;
}
.modal-body2.modal2-fadeOut:before {
opacity: 0;
}
.modal2 {
transition: all ease 0.01s;
display: block;
opacity: 0;
height: 0;
position: fixed;
content: '';
top: 0;
left: 0;
right: 0;
z-index: 2000;
text-align: center;
overflow: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modal2.modal2-visible {
opacity: 1;
height: auto;
bottom: 0;
}
.modal-inner2 {
transition: all ease 320ms;
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
position: relative;
display: inline-block;
background-color: #fff;
width: 90%;
max-width: 600px;
background: #fff;
opacity: 0;
margin: 40px 0;
border-radius: 4px;
box-shadow: 0 30px 18px -20px #020202;
}
.modal-inner2.modal2-reveal {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
.js-close-modal2 {
transition: color 320ms ease;
color: #9e9e9e;
opacity: 0.75;
position: absolute;
z-index: 2;
right: 0px;
top: 0px;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 20px;
cursor: pointer;
text-align: center;
}
.js-close-modal2:hover {
color: #000;
}
Script for modal that WORKS
const modal = () => {
'use strict';
class Modal {
constructor() {
this.triggers = document.querySelectorAll('.js-modal');
this.close = document.querySelectorAll('.js-close-modal');
this.modals = document.querySelectorAll('.modal');
this.modalInners = document.querySelectorAll('.modal-inner');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal.hideModal, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body')) {
Modal.hideModal();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal.hideModal();
}
}
static hideModal() {
let modalOpen = document.querySelector('.modal.modal-visible');
modalOpen.querySelector('.modal-inner').classList.remove('modal-reveal');
document.querySelector('.modal-body').addEventListener('transitionend', Modal.modalBody, false);
document.body.classList.add('modal-fadeOut');
}
closeModal(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal-reveal')) {
document.querySelector('.modal.modal-visible').classList.remove('modal-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modalID = el.currentTarget.dataset.modal;
let modal = document.getElementById(modalID);
document.body.classList.add('modal-body');
modal.classList.add('modal-visible');
}
revealModal(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal-visible')) {
el.target.querySelector('.modal-inner').classList.add('modal-reveal');
}
}
static modalBody(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal') && !el.target.classList.contains('modal-visible')) {
document.body.classList.remove('modal-body', 'modal-fadeOut');
}
}}
new Modal();
};
export default modal;
Script for modal that does NOT WORK
const modal2 = () => {
'use strict';
class Modal2 {
constructor() {
this.triggers = document.querySelectorAll('.js-modal2');
this.close = document.querySelectorAll('.js-close-modal2');
this.modals = document.querySelectorAll('.modal2');
this.modalInners = document.querySelectorAll('.modal-inner2');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal2, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal2, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal2.hideModal2, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal2, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body2')) {
Modal2.hideModal2();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal2-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal2.hideModal2();
}
}
static hideModal2() {
let modalOpen = document.querySelector('.modal2.modal2-visible');
modalOpen.querySelector('.modal-inner2').classList.remove('modal2-reveal');
document.querySelector('.modal-body2').addEventListener('transitionend', Modal2.modalBody2, false);
document.body.classList.add('modal2-fadeOut');
}
closeModal2(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal2-reveal')) {
document.querySelector('.modal2.modal2-visible').classList.remove('modal2-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modal2ID = el.currentTarget.dataset.modal2;
let modal2 = document.getElementById(modal2ID);
document.body.classList.add('modal-body2');
modal.classList.add('modal2-visible');
}
revealModal2(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal2-visible')) {
el.target.querySelector('.modal-inner2').classList.add('modal2-reveal');
}
}
static modalBody2(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal2') && !el.target.classList.contains('modal2-visible')) {
document.body.classList.remove('modal-body2', 'modal2-fadeOut');
}
}}
new Modal2();
};
export default modal2;
in your javascript, this.triggers refer to your button but in your function openModal the variable modal2ID is undefined because your button doesn't have dataset.modal2

Why the last child of unordered list is not always animated as expected?

I want to make a simple filterable gallery with plain JavaScript. I made a pen in codepen, in which I'm doing some experiments with colored divs. It still has a lot of work in order to make a better javascript code, but there is a weird behavior which I cannot see why is happening.
The strange behavior has to do with the last child of the list, which isn't always animated as expected. To be more specific:
-If I just select the "yellow" button, all filtered yellow boxes will animate as expected.
-If I first select the "all" button and then I select the "yellow" button, the 10th box isn't animated.
I tried several different things and I noticed that the problem is with the last child of list. For example, I deleted the 6,7,8,9,10 and then the same problem appeared with the fifth box.
I've also tried to completely remove the CSS child selector but the weird behavior still existed.
Any ideas why this might be happening?
https://codepen.io/FoteiniK/pen/oJmbeJ?editors=1010
const allButton = document.getElementById("all");
const listItems = document.getElementsByClassName("item");
const blueButton = document.getElementById("blue");
const yellowButton = document.getElementById("yellow");
const redButton = document.getElementById("red")
const list = document.getElementById("list");
blueButton.onclick = () => {
for (let item of listItems) {
/*reset animation*/
item.style.animation = " ";
item.offsetHeight;
item.style.animation = null;
item.classList.remove("appear-items", "dissappear");
item.classList.contains("blue") === false &&
item.classList.add("dissappear");
}
list.classList.add("reorder");
};
yellowButton.onclick = () => {
for (let item of listItems) {
item.style.animation = " ";
item.offsetHeight;
item.style.animation = null;
item.classList.remove("dissappear", "appear-items");
item.classList.contains("yellow") ===
false && item.classList.add("dissappear");
}
list.classList.add("reorder");
};
redButton.onclick = () => {
for (let item of listItems) {
item.style.animation = " ";
item.offsetHeight;
item.style.animation = null;
item.classList.remove("dissappear", "appear-items");
item.classList.contains("red") ===
false && item.classList.add("dissappear");
}
list.classList.add("reorder");
};
allButton.onclick = () => {
list.classList.remove("reorder");
for (let item of listItems) {
item.style.animation = " ";
item.offsetHeight;
item.style.animation = null;
item.classList.remove("dissappear");
item.classList.add("appear-items");
}
};
$time:0.6s;
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: inherit;
}
body {
box-sizing: border-box;
}
.container {
display: flex;
background-color: #afafaf;
margin: 20px;
}
.list {
list-style: none;
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.item {
order: 10;
padding: 30px;
background-color: #e12345;
margin: 10px;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.buttons {
display: flex;
flex-direction: column;
justify-content: space-evenly;
& button {
padding: 10px;
margin: 3px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.6;
}
}
}
.reorder {
// .item{
// animation:appear 0.5s;
// }
.item:nth-child(1) {
animation: appear $time ease-in;
order: 0;
}
.item:nth-child(2) {
animation: appear $time ease-in;
order: 1;
}
.item:nth-child(3) {
animation: appear $time ease-in;
order: 2;
}
.item:nth-child(4) {
animation: appear $time ease-in;
order: 5;
}
.item:nth-child(5) {
animation: appear $time ease-in;
order: 4;
}
.item:nth-child(6) {
animation: appear $time ease-in;
order: 2;
}
.item:nth-child(7) {
animation: appear $time ease-in;
order: 1;
}
.item:nth-child(8) {
animation: appear $time ease-in;
order: 0;
}
.item:nth-child(9) {
animation: appear $time ease-in;
order: 0;
}
.item:nth-child(10) {
animation: appear $time ease-in;
order: 1;
}
}
.appear-items {
animation: appear 0.5s;
}
#keyframes appear {
0% {
opacity: 0;
transform: scale3d(0.1, 0.1, 0.1);
}
20% {
opacity: 0.2;
transform: scale3d(0.2, 0.2, 0.2);
}
40% {
opacity: 0.4;
transform: scale3d(0.4, 0.4, 0.4);
}
60% {
opacity: 0.6;
transform: scale3d(0.6, 0.6, 0.6) translateY(0);
}
80% {
opacity: 0.8;
transform: scale3d(0.8, 0.8, 0.8);
}
100% {
opacity: 1;
transform: scale3d(1, 1, 1);
}
}
.dissappear {
display: none;
}
<div class="container">
<div class="buttons">
<button class="all but" id="all">all</button>
<button class="blue but" id="blue">blue</button>
<button class="yellow but" id="yellow">yellow</button>
<button class="red but" id="red">red</button>
</div>
<ul class="list" id="list">
<li class="item blue">1</li>
<li class="item red">2</li>
<li class="item yellow">3</li>
<li class="item red">4</li>
<li class="item yellow">5</li>
<li class="item red">6</li>
<li class="item yellow">7</li>
<li class="item blue">8</li>
<li class="item red">9</li>
<li class="item yellow">10</li>
</ul>
</div>

Categories

Resources