memory js game pictures won't close - javascript

I found one game on js, and I want to add it to myself by redoing it a bit
https://jsfiddle.net/a7Lx1c98/
So, I want to replace emoji with pictures here, I do this
const emojis = ['https://i.imgur.com/GLS9S5f.jpg', 'https://i.imgur.com/IN9C2qz.jpg', 'https://i.imgur.com/Ke2ubzv.jpg', 'https://i.imgur.com/PbvJDyR.jpg', 'https://i.imgur.com/L3ysai2.jpg',
'https://i.imgur.com/1NxzhTV.jpg', 'https://i.imgur.com/aksV9O3.jpg', 'https://i.imgur.com/gYsZdE4.jpg', 'https://i.imgur.com/LXo6iW3.jpg', 'https://i.imgur.com/wYrEwNR.jpg']
const picks = pickRandom(emojis, (dimensions * dimensions) / 2)
const items = shuffle([...picks, ...picks])
const cards = `
<div class="board" style="grid-template-columns: repeat(${dimensions}, auto)">
${items.map(item => `
<div class="card">
<div class="card-front"></div>
<div class="card-back"><img src="${item}"></div>
</div>
`).join('')}
</div>
`
As a result, the pictures appear, but the game itself does not work, when you select two pictures and they are different, they do not close, but you can choose everything in a row
What could be wrong?
const selectors = {
boardContainer: document.querySelector('.board-container'),
board: document.querySelector('.board'),
moves: document.querySelector('.moves'),
timer: document.querySelector('.timer'),
start: document.querySelector('button'),
win: document.querySelector('.win')
}
const state = {
gameStarted: false,
flippedCards: 0,
totalFlips: 0,
totalTime: 0,
loop: null
}
const shuffle = array => {
const clonedArray = [...array]
for (let index = clonedArray.length - 1; index > 0; index--) {
const randomIndex = Math.floor(Math.random() * (index + 1))
const original = clonedArray[index]
clonedArray[index] = clonedArray[randomIndex]
clonedArray[randomIndex] = original
}
return clonedArray
}
const pickRandom = (array, items) => {
const clonedArray = [...array]
const randomPicks = []
for (let index = 0; index < items; index++) {
const randomIndex = Math.floor(Math.random() * clonedArray.length)
randomPicks.push(clonedArray[randomIndex])
clonedArray.splice(randomIndex, 1)
}
return randomPicks
}
const generateGame = () => {
const dimensions = selectors.board.getAttribute('data-dimension')
if (dimensions % 2 !== 0) {
throw new Error("The dimension of the board must be an even number.")
}
const emojis = ['https://i.imgur.com/GLS9S5f.jpg', 'https://i.imgur.com/IN9C2qz.jpg', 'https://i.imgur.com/Ke2ubzv.jpg', 'https://i.imgur.com/PbvJDyR.jpg', 'https://i.imgur.com/L3ysai2.jpg',
'https://i.imgur.com/1NxzhTV.jpg', 'https://i.imgur.com/aksV9O3.jpg', 'https://i.imgur.com/gYsZdE4.jpg', 'https://i.imgur.com/LXo6iW3.jpg', 'https://i.imgur.com/wYrEwNR.jpg']
const picks = pickRandom(emojis, (dimensions * dimensions) / 2)
const items = shuffle([...picks, ...picks])
const cards = `
<div class="board" style="grid-template-columns: repeat(${dimensions}, auto)">
${items.map(item => `
<div class="card">
<div class="card-front"></div>
<div class="card-back"><img src="${item}"></div>
</div>
`).join('')}
</div>
`
const parser = new DOMParser().parseFromString(cards, 'text/html')
selectors.board.replaceWith(parser.querySelector('.board'))
}
const startGame = () => {
state.gameStarted = true
selectors.start.classList.add('disabled')
state.loop = setInterval(() => {
state.totalTime++
selectors.moves.innerText = `${state.totalFlips} moves`
selectors.timer.innerText = `time: ${state.totalTime} sec`
}, 1000)
}
const flipBackCards = () => {
document.querySelectorAll('.card:not(.matched)').forEach(card => {
card.classList.remove('flipped')
})
state.flippedCards = 0
}
const flipCard = card => {
state.flippedCards++
state.totalFlips++
if (!state.gameStarted) {
startGame()
}
if (state.flippedCards <= 2) {
card.classList.add('flipped')
}
if (state.flippedCards === 2) {
const flippedCards = document.querySelectorAll('.flipped:not(.matched)')
if (flippedCards[0].innerText === flippedCards[1].innerText) {
flippedCards[0].classList.add('matched')
flippedCards[1].classList.add('matched')
}
setTimeout(() => {
flipBackCards()
}, 1000)
}
// If there are no more cards that we can flip, we won the game
if (!document.querySelectorAll('.card:not(.flipped)').length) {
setTimeout(() => {
selectors.boardContainer.classList.add('flipped')
selectors.win.innerHTML = `
<span class="win-text">
You won!<br />
with <span class="highlight">${state.totalFlips}</span> moves<br />
under <span class="highlight">${state.totalTime}</span> seconds
</span>
`
clearInterval(state.loop)
}, 1000)
}
}
const attachEventListeners = () => {
document.addEventListener('click', event => {
const eventTarget = event.target
const eventParent = eventTarget.parentElement
if (eventTarget.className.includes('card') && !eventParent.className.includes('flipped')) {
flipCard(eventParent)
} else if (eventTarget.nodeName === 'BUTTON' && !eventTarget.className.includes('disabled')) {
startGame()
}
})
}
generateGame()
attachEventListeners()
html {
width: 100%;
height: 100%;
background: linear-gradient(325deg, #6f00fc 0%,#fc7900 50%,#fcc700 100%);
font-family: Fredoka;
}
.game {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.controls {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
button {
background: #282A3A;
color: #FFF;
border-radius: 5px;
padding: 10px 20px;
border: 0;
cursor: pointer;
font-family: Fredoka;
font-size: 18pt;
}
.disabled {
color: #757575;
}
.stats {
color: #FFF;
font-size: 14pt;
}
.board-container {
position: relative;
}
.board,
.win {
border-radius: 5px;
box-shadow: 0 25px 50px rgb(33 33 33 / 25%);
background: linear-gradient(135deg, #6f00fc 0%,#fc7900 50%,#fcc700 100%);
transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1);
backface-visibility: hidden;
}
.board {
padding: 20px;
display: grid;
grid-template-columns: repeat(4, auto);
grid-gap: 20px;
}
.board-container.flipped .board {
transform: rotateY(180deg) rotateZ(50deg);
}
.board-container.flipped .win {
transform: rotateY(0) rotateZ(0);
}
.card {
position: relative;
width: 100px;
height: 100px;
cursor: pointer;
}
.card-front,
.card-back {
position: absolute;
border-radius: 5px;
width: 100%;
height: 100%;
background: #282A3A;
transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1);
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg) rotateZ(50deg);
font-size: 28pt;
user-select: none;
text-align: center;
line-height: 100px;
background: #FDF8E6;
}
.card.flipped .card-front {
transform: rotateY(180deg) rotateZ(50deg);
}
.card.flipped .card-back {
transform: rotateY(0) rotateZ(0);
}
.win {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
background: #FDF8E6;
transform: rotateY(180deg) rotateZ(50deg);
}
.win-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 21pt;
color: #282A3A;
}
.highlight {
color: #6f00fc;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
<!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>🧠 Memory Game in JavaScript</title>
<link rel="stylesheet" href="assets/styles.css" />
<script src="assets/game.js" defer></script>
</head>
<body>
<div class="game">
<div class="controls">
<button>Start</button>
<div class="stats">
<div class="moves">0 moves</div>
<div class="timer">time: 0 sec</div>
</div>
</div>
<div class="board-container">
<div class="board" data-dimension="4"></div>
<div class="win">You won!</div>
</div>
</div>
</body>
</html>

Because every pair is a match:
if (flippedCards[0].innerText === flippedCards[1].innerText)
Your elements have no text, so innerText is always an empty string. So any two cards, regardless of their images, match.
Probably the quickest solution is to compare the HTML instead:
if (flippedCards[0].innerHTML === flippedCards[1].innerHTML)
Assuming the rest of the HTML is always the same, the only different should be the src on the <img> element(s).
As an added exercise, you could also look into being more explicit in that comparison. Perhaps give each element a data-* property and compare those instead of relying on the text or HTML. Or perhaps specifically read the src property and compare those values instead of comparing the entire contents of the element(s).

The issue is comparing the innerText of the two cards. There is no inner text, so you can compare the card back image URLs.
const selected = [...flippedCards].map(card => card.querySelector('.card-back img').src);
if (allEqual(selected)) {
flippedCards[0].classList.add('matched')
flippedCards[1].classList.add('matched')
}
I also added an allEqual function to make sure all the items match:
const allEqual = arr => arr.every(v => v === arr[0]);
Working example
const allEqual = arr => arr.every(v => v === arr[0]);
const selectors = {
boardContainer: document.querySelector('.board-container'),
board: document.querySelector('.board'),
moves: document.querySelector('.moves'),
timer: document.querySelector('.timer'),
start: document.querySelector('button'),
win: document.querySelector('.win')
};
const state = {
gameStarted: false,
flippedCards: 0,
totalFlips: 0,
totalTime: 0,
loop: null
};
const shuffle = array => {
const clonedArray = [...array];
for (let index = clonedArray.length - 1; index > 0; index--) {
const randomIndex = Math.floor(Math.random() * (index + 1));
const original = clonedArray[index];
clonedArray[index] = clonedArray[randomIndex];
clonedArray[randomIndex] = original;
}
return clonedArray;
}
const pickRandom = (array, items) => {
const clonedArray = [...array];
const randomPicks = [];
for (let index = 0; index < items; index++) {
const randomIndex = Math.floor(Math.random() * clonedArray.length);
randomPicks.push(clonedArray[randomIndex]);
clonedArray.splice(randomIndex, 1);
}
return randomPicks;
}
const generateGame = () => {
const dimensions = selectors.board.getAttribute('data-dimension');
if (dimensions % 2 !== 0) {
throw new Error("The dimension of the board must be an even number.");
}
const emojis = [
'https://i.imgur.com/GLS9S5f.jpg',
'https://i.imgur.com/IN9C2qz.jpg',
'https://i.imgur.com/Ke2ubzv.jpg',
'https://i.imgur.com/PbvJDyR.jpg',
'https://i.imgur.com/L3ysai2.jpg',
'https://i.imgur.com/1NxzhTV.jpg',
'https://i.imgur.com/aksV9O3.jpg',
'https://i.imgur.com/gYsZdE4.jpg',
'https://i.imgur.com/LXo6iW3.jpg',
'https://i.imgur.com/wYrEwNR.jpg'
];
const picks = pickRandom(emojis, (dimensions * dimensions) / 2);
const items = shuffle([...picks, ...picks]);
const cards = `
<div class="board" style="grid-template-columns: repeat(${dimensions}, auto)">
${items.map(item => `
<div class="card">
<div class="card-front"></div>
<div class="card-back"><img src="${item}"></div>
</div>
`).join('')}
</div>
`;
const parser = new DOMParser().parseFromString(cards, 'text/html');
selectors.board.replaceWith(parser.querySelector('.board'));
}
const startGame = () => {
state.gameStarted = true
selectors.start.classList.add('disabled');
state.loop = setInterval(() => {
state.totalTime++;
selectors.moves.innerText = `${state.totalFlips} moves`;
selectors.timer.innerText = `time: ${state.totalTime} sec`;
}, 1000);
}
const flipBackCards = () => {
document.querySelectorAll('.card:not(.matched)').forEach(card => {
card.classList.remove('flipped');
})
state.flippedCards = 0;
}
const flipCard = card => {
state.flippedCards++;
state.totalFlips++;
if (!state.gameStarted) {
startGame();
}
if (state.flippedCards <= 2) {
card.classList.add('flipped');
}
if (state.flippedCards === 2) {
const flippedCards = document.querySelectorAll('.flipped:not(.matched)')
const selected = [...flippedCards].map(card => card.querySelector('.card-back img').src);
if (allEqual(selected)) {
flippedCards[0].classList.add('matched')
flippedCards[1].classList.add('matched')
}
setTimeout(() => {
flipBackCards();
}, 1000);
}
// If there are no more cards that we can flip, we won the game
if (!document.querySelectorAll('.card:not(.flipped)').length) {
setTimeout(() => {
selectors.boardContainer.classList.add('flipped');
selectors.win.innerHTML = `
<span class="win-text">
You won!<br />
with <span class="highlight">${state.totalFlips}</span> moves<br />
under <span class="highlight">${state.totalTime}</span> seconds
</span>
`;
clearInterval(state.loop);
}, 1000);
}
}
const attachEventListeners = () => {
document.addEventListener('click', event => {
const eventTarget = event.target;
const eventParent = eventTarget.parentElement;
if (eventTarget.className.includes('card') && !eventParent.className.includes('flipped')) {
flipCard(eventParent);
} else if (eventTarget.nodeName === 'BUTTON' && !eventTarget.className.includes('disabled')) {
startGame();
}
})
}
generateGame();
attachEventListeners();
html {
width: 100%;
height: 100%;
background: linear-gradient(325deg, #6f00fc 0%, #fc7900 50%, #fcc700 100%);
font-family: Fredoka;
}
.game {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.controls {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
button {
background: #282A3A;
color: #FFF;
border-radius: 5px;
padding: 10px 20px;
border: 0;
cursor: pointer;
font-family: Fredoka;
font-size: 18pt;
}
.disabled {
color: #757575;
}
.stats {
color: #FFF;
font-size: 14pt;
}
.board-container {
position: relative;
}
.board,
.win {
border-radius: 5px;
box-shadow: 0 25px 50px rgb(33 33 33 / 25%);
background: linear-gradient(135deg, #6f00fc 0%, #fc7900 50%, #fcc700 100%);
transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1);
backface-visibility: hidden;
}
.board {
padding: 20px;
display: grid;
grid-template-columns: repeat(4, auto);
grid-gap: 20px;
}
.board-container.flipped .board {
transform: rotateY(180deg) rotateZ(50deg);
}
.board-container.flipped .win {
transform: rotateY(0) rotateZ(0);
}
.card {
position: relative;
width: 100px;
height: 100px;
cursor: pointer;
}
.card-front,
.card-back {
position: absolute;
border-radius: 5px;
width: 100%;
height: 100%;
background: #282A3A;
transition: transform .6s cubic-bezier(0.4, 0.0, 0.2, 1);
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg) rotateZ(50deg);
font-size: 28pt;
user-select: none;
text-align: center;
line-height: 100px;
background: #FDF8E6;
}
.card.flipped .card-front {
transform: rotateY(180deg) rotateZ(50deg);
}
.card.flipped .card-back {
transform: rotateY(0) rotateZ(0);
}
.win {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
background: #FDF8E6;
transform: rotateY(180deg) rotateZ(50deg);
}
.win-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 21pt;
color: #282A3A;
}
.highlight {
color: #6f00fc;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="game">
<div class="controls">
<button>Start</button>
<div class="stats">
<div class="moves">0 moves</div>
<div class="timer">time: 0 sec</div>
</div>
</div>
<div class="board-container">
<div class="board" data-dimension="4"></div>
<div class="win">You won!</div>
</div>
</div>

Related

why disableEnable and imgSrc function show typescript error?

previous
<svg
class="get-carousel__prev-svg"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 512 512"
>
Chevron Back
<button
class="gel-carousel__next get-carousel__buttons_back"
ref="next"
aria-label="next "
#click="nextShift"
type="button"
>
next
Chevron Forward
<div
class="gel-carousel__scrollable"
ref="gallery"
#scroll="carouselScroll"
>
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
Mohtasim Hasan
import { onMounted, ref } from "vue";
let debounced = ref();
const gallery = ref();
const lists = ref();
const previous = ref();
const next = ref();
const buttons = ref();
onMounted(() => {
const slides = document.querySelectorAll("img[data-src]");
buttons.value?.removeAttribute("hidden");
disableEnable();
let observer = new IntersectionObserver(imgSrcSet, {
root: null,
threshold: 0.6,
});
slides.forEach((slide) => {
observer.observe(slide);
});
});
const carouselScroll = () => {
window.clearTimeout(debounced.value);
debounced.value = setTimeout(disableEnable, 250);
};
const disableEnable = function () {
previous.value.disabled = gallery.value?.scrollLeft {
if (entry.intersectionRatio > 0.5) {
entry.target.closest("li").removeAttribute("inert");
console.log(entry);
entry.target.setAttribute("src", entry.target.dataset.src);
entry.target.src = entry.target.dataset.src;
}
if (!entry.isIntersecting) {
entry.target.closest("li").setAttribute("inert", "");
entry.target.closest("li").setAttribute("tabindex", -1);
}
if (entry.isIntersecting) {
entry.target.closest("li").setAttribute("tabindex", 0);
}
});
};
const previousShift = function () {
const scrollPos = ref(gallery.value?.scrollWidth / 4);
gallery.value?.scrollTo(gallery.value?.scrollLeft - scrollPos.value, 0);
};
const nextShift = function () {
const scrollPos = ref(gallery.value?.scrollWidth / 4);
gallery.value?.scrollTo(
gallery.value?.scrollLeft + 400,
gallery.value.scrollTop
);
};
.gel-carousel__buttons {
button {
cursor: pointer;
}
button[disabled] {
cursor: no-drop;
}
}
.gel-carousel__list {
display: flex;
list-style: none;
padding: 0;
margin: 0;
white-space: nowrap;
}
.gel-carousel__list > li {
display: flex;
flex-shrink: 0;
white-space: normal;
width: var(--size-fluid-9); /* standard Promo width */
transition: all 0.5s linear;
position: relative;
figure {
display: flex;
justify-items: space-between;
flex-direction: column;
margin: 0;
padding: 0;
}
figcaption {
margin-block: 2rem;
}
img {
display: block;
width: 100%;
height: var(--size-fluid-8);
background-size: cover;
transition: all 0.3s linear;
}
}
.gel-carousel__list > li[inert] {
opacity: 0.6;
}
ul {
padding: 0;
margin: 0;
}
.gel-carousel__list > li + li {
margin-left: 1rem;
&:not(:last-child) {
margin-left: 0;
}
}
.gel-carousel__scrollable {
width: 50rem;
overflow: auto;
scroll-behavior: smooth;
}
#media (prefers-reduced-motion: reduce) {
.gel-carousel__scrollable {
scroll-behavior: auto;
}
}
.gel-carousel__scrollable::-webkit-scrollbar {
height: 0.8rem;
}
.gel-carousel__scrollable::-webkit-scrollbar-track {
background-color: lightblue;
}
.gel-carousel__scrollable::-webkit-scrollbar-thumb {
background-color: lightpink;
}
.gel-sr:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
I created a vue js carousel app with typescript. But in it shows red squiggly line on both fuction.

GPT injecting between content of infinite scroll

I have created a simple boilerplate to test GPT injection using infinite scroll however when the unit loads its at the bottom of the page, but I need it to load at the bottom of the page and then more content load below it.
I can't see what mistake i have made and the changes i need to make to remedy this. All help is great and thankful.
I want it to show 7,8,9 ad 10,11,12
the code snippet doesn't work correctly so for example use link:
Live test page example
const cardContainer = document.getElementById("card-container");
const cardCountElem = document.getElementById("card-count");
const cardTotalElem = document.getElementById("card-total");
const loader = document.getElementById("loader");
const cardLimit = 99;
const cardIncrease = 9;
const pageCount = Math.ceil(cardLimit / cardIncrease);
let currentPage = 1;
cardTotalElem.innerHTML = cardLimit;
var throttleTimer;
const throttle = (callback, time) => {
if (throttleTimer) return;
throttleTimer = true;
setTimeout(() => {
callback();
throttleTimer = false;
}, time);
};
const getRandomColor = () => {
const h = Math.floor(Math.random() * 360);
return `hsl(${h}deg, 90%, 85%)`;
};
const createCard = (index) => {
const card = document.createElement("div");
card.className = "card";
card.innerHTML = index;
card.style.backgroundColor = getRandomColor();
cardContainer.appendChild(card);
};
const addCards = (pageIndex) => {
currentPage = pageIndex;
const startRange = (pageIndex - 1) * cardIncrease;
const endRange =
currentPage == pageCount ? cardLimit : pageIndex * cardIncrease;
cardCountElem.innerHTML = endRange;
for (let i = startRange + 1; i <= endRange; i++) {
createCard(i);
}
};
const handleInfiniteScroll = () => {
throttle(() => {
const endOfPage =
window.innerHeight + window.pageYOffset >= document.body.offsetHeight;
if (endOfPage) {
moreContent();
addCards(currentPage + 1);
}
if (currentPage === pageCount) {
removeInfiniteScroll();
}
}, 1000);
};
const removeInfiniteScroll = () => {
loader.remove();
window.removeEventListener("scroll", handleInfiniteScroll);
};
window.onload = function () {
addCards(currentPage);
};
window.addEventListener("scroll", handleInfiniteScroll);
body {
font-family: "Roboto", sans-serif;
}
#card-container {
display: flex;
flex-wrap: wrap;
}
.card {
height: 55vh;
width: calc((100% / 3) - 16px);
margin: 8px;
border-radius: 3px;
transition: all 200ms ease-in-out;
display: flex;
align-items: center;
justify-content: center;
}
.card:hover {
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.card-actions {
margin: 8px;
padding: 16px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
#loader {
display: flex;
}
.skeleton-card {
height: 55vh;
width: calc((100% / 3) - 16px);
margin: 8px;
border-radius: 3px;
transition: all 200ms ease-in-out;
position: relative;
background-color: #eaeaea;
}
.skeleton-card::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translateX(-100%);
background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0));
animation: load 1s infinite;
}
#keyframes load {
100% {
transform: translateX(100%);
}
}
#media screen and (prefers-reduced-motion: reduce) {
.skeleton-card::after {
animation: none;
}
}
<script src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
<script src="https://naughty-swanson.78-24-89177.plesk.page/Matrix/test_matrix.js"></script>
<div id="leaderboard">
<script>
// Call display() to register the slot as ready and fetch an ad.
googletag.cmd.push(function() {
googletag.display('leaderboard');
});
</script>
</div>
<div id="card-container">
</div>
<div>
</div>
<div id="loader">
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
</div>
<div class="card-actions">
<span>Showing
<span id="card-count"></span> of
<span id="card-total"></span> cards
</span>
</div>

change background colour of div on carousel

I'm trying to get to grips with javascript, and have followed a tutorial for a simple image slider. I'm trying to add to it and have the background fade to different colours as the slides move. I've managed to figure it out with the right and left arrows (not sure on best practise), but I can't seem to get it right when selecting the indicators. Can anyone advise on a solution?
Thanks in advance.
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
var background = 1;
function indicatorBg(val){
var background = val;
changeBg();
}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background <= 1) {
return false;
} else {
background--;
}
changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background >= 4) {
return false;
} else {
background++;
}
changeBg();
});
function changeBg (){
if (background == 1) {
document.getElementById("carousel__track").className = 'slide-1';
} else if (background == 2) {
document.getElementById("carousel__track").className = 'slide-2';
} else if (background == 3) {
document.getElementById("carousel__track").className = 'slide-3';
} else if (background == 4) {
document.getElementById("carousel__track").className = 'slide-4';
}
}
window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" onclick="indicatorBg(this.value)" class="selected"></li>
<li value="2" onclick="indicatorBg(this.value)"></li>
<li value="3" onclick="indicatorBg(this.value)"></li>
<li value="4" onclick="indicatorBg(this.value)"></li>
</ol>
</div>
</div>
</section>
You forgot to change the background inside the click event handler of the indicators.
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
background = index + 1;
changeBg();
});
});
As far as best practice goes, I typically use class names for CSS and IDs for JavaScript. Personally, I wouldn't recommend you worry about best practices at this stage, but instead, focus on getting the code working and understanding what's going on line-by-line.
There is a lot of solutions, but the simplest solution that I advice is to use odd and even numbers to style the divs in the carousel (meaning that eg. first is green second is orange third is green and so on...
.carousel__slider div:nth-child(2n) /*Selects even numbered elements*/
.carousel__slider div:nth-child(2n+1) /*Selects odd numbered elements*/
Check out the snippet
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
//var background = 1;
//function indicatorBg(val){
// var background = val;
// changeBg();
//}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background <= 1) {
// return false;
// } else {
// background--;
// }
// changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background >= 4) {
// return false;
// } else {
// background++;
// }
// changeBg();
});
//function changeBg (){
// if (background == 1) {
// document.getElementById("carousel__track").className = 'slide-1';
// } else if (background == 2) {
// document.getElementById("carousel__track").className = 'slide-2';
// } else if (background == 3) {
// document.getElementById("carousel__track").className = 'slide-3';
// } else if (background == 4) {
// document.getElementById("carousel__track").className = 'slide-4';
// }
//}
//window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
/*.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}*/
.carousel__slider div:nth-child(2n) {
background-color:orange;
}
.carousel__slider div:nth-child(2n+1) {
background-color:green;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" class="selected"></li>
<li value="2" ></li>
<li value="3" ></li>
<li value="4" ></li>
</ol>
</div>
</div>
</section>

<a class='gotoLine' href='#230:45'>230:45</a> Uncaught TypeError :

"230:45 Uncaught TypeError: Cannot read properties of undefined (reading 'shouldStopExecution')"
I got the following error can you fix it. I am trying to add HTML, CSS, and javascript on the same page.
I found this code in codepen i am trying to solve the issue but it's not working anymore...
But javascript not working here...
<div class="wrapper">
<div class="poll-box">
<div class="poll-container">
<div class="poll-question">Do You Love to Play FreeFire?</div>
<div class="poll-panel row mt-30">
<div class="btn poll-panel-btn" aria-role="button" data-result="0" data-vote="0"> <span>Yes</span></div>
<div class="btn poll-panel-btn" aria-role="button" data-result="0" data-vote="1"> <span>No</span></div>
</div>
</div>
</div>
</div>
<style>* {
box-sizing: border-box;
}
body {
background: #1b1b1b;
margin: 0;
}
.wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.mt-30 {
margin: 30px 0 0 0;
}
.row, .column {
display: flex;
}
.row {
flex-direction: row;
}
.column {
flex-direction: column;
}
.btn:not([disabled]) {
cursor: pointer;
}
.poll-box {
background: linear-gradient(#803af7, #500cc4);
border-radius: 3px;
box-shadow: 0px 5px 11px -7px #000;
text-align: center;
}
.poll-container {
padding: 25px 30px;
position: relative;
}
.poll-question {
width: max-content;
max-width: 700px;
color: #FFF;
font-family: "Poppins", sans-serif;
}
.poll-panel.poll-voted {
overflow: hidden;
border-radius: 50px;
}
.poll-panel.poll-voted .poll-panel-btn.--user-choice {
background: #FFF;
color: #000;
}
.poll-panel.poll-voted .poll-panel-btn.--user-choice:hover {
color: #000;
background: #FFF;
}
.poll-panel.poll-voted .poll-panel-btn {
background: #676464;
color: #FFF;
border-radius: 0;
margin: 0;
border: 0;
position: relative;
}
.poll-panel.poll-voted .poll-panel-btn:hover {
color: #FFF;
background: #676464;
}
.poll-panel.poll-voted .poll-panel-btn:after {
content: attr(data-result);
font-size: 9px;
display: block;
opacity: 0.5;
animation: slideWithFade 0.2s ease;
}
.poll-panel.poll-voted .poll-panel-btn:active {
transform: inherit;
}
.poll-panel.poll-voted .poll-panel-btn span {
display: block;
}
.poll-panel {
width: 100%;
}
.poll-panel-btn {
padding: 7px 10px;
font-family: "Roboto", sans-serif;
font-size: 0.7rem;
width: 100%;
border-radius: 50px;
border: 1px solid #FFF;
margin: 0 20px;
color: #FFF;
transition: 0.15s cubic-bezier(0.17, 0.67, 0.79, 1.24);
}
.poll-panel-btn:hover {
background: #FFF;
color: #000;
}
.poll-panel-btn:active {
transform: scale(0.95);
}
#keyframes slideWithFade {
0% {
opacity: 0;
transform: translateY(10px);
}
100% {
opacity: 1;
}
}</style>
<script>// POLL PLUGIN
class poll {
constructor(question, answers, options) {
const defaultOptions = {};
this.options = Object.assign({}, defaultOptions, options);
this.history = [];
this.possibleAnswers = answers;
}
clear() {
this.history = [];
}
get results() {
let numberOfVotes = this.history.length,
votesResults = [];
Object.keys(this.possibleAnswers).forEach(answerId => {
let answerIdCounter = 0;
let voters = [];
this.history.forEach(vote => {
if (answerId == vote.id) {
answerIdCounter++;
voters.push(vote.name);
}
});
let percentOfAllVotes = answerIdCounter / numberOfVotes * 100;
let formatedPercent = isNaN(percentOfAllVotes) ?
0 :
parseFloat(percentOfAllVotes).
toFixed(3).
slice(0, -1);
votesResults.push({
votes: answerIdCounter,
voters: voters,
percent: formatedPercent });
});
return votesResults;
}
vote(answerId, name = "Anonymouse") {
if (this.possibleAnswers[answerId]) {
let getCurrentDate = new Date().toLocaleString();
this.history.push({ id: answerId, name: name, date: getCurrentDate });
return true;
} else throw new Error("Incorrect answer's id");
}}
// Plugin: https://codepen.io/badurski/pen/RJvJQZ
const q1 = new poll("Will Poland win the footboal match?", {
0: { title: "Yes" },
1: { title: "No" } });
// Add some randome votes
for (let i = 0; i < 20; i++) {if (window.CP.shouldStopExecution(0)) break;
q1.vote(Math.floor(Math.random() * (1 - 0 + 1)) + 0);
}
// Poll interface script
window.CP.exitedLoop(0);let pollButtons = document.querySelectorAll('.poll-panel-btn'),
pollPanel = document.querySelector('.poll-panel');
pollButtons.forEach(button => {
button.onclick = () => {
if (button.getAttribute('disabled') != 'disabled') {
q1.vote(button.dataset.vote);
pollPanel.classList.add('poll-voted');
button.classList.add('--user-choice');
pollButtons.forEach(b => {
b.setAttribute('disabled', 'disabled');
let percent = q1.results[b.dataset.vote].percent + '%';
b.style.width = percent;
b.dataset.result = percent;
});
}
};
});</script>
In codepen everything is separated but in your HTML you should put the scripts before the divs.
Something like:
<script>
//blabla.yourscripts - you got it
</script>
<div class="wrapper">
<div class="poll-box">
<div class="poll-container">
<div class="poll-question">Do You Love to Play FreeFire?</div>
<div class="poll-panel row mt-30">
<div class="btn poll-panel-btn" aria-role="button" data-result="0" data-vote="0"> <span>Yes</span></div>
<div class="btn poll-panel-btn" aria-role="button" data-result="0" data-vote="1"> <span>No</span></div>
</div>
</div>
</div>
</div>
So just put the scripts before the stuff reading them.
You have included CP which is the CodePan component.
Please remove window.CP lines, then it will work:
window.CP.exitedLoop(0);
if (window.CP.shouldStopExecution(0)) break;
<script>
// POLL PLUGIN
class poll {
constructor(question, answers, options) {
const defaultOptions = {};
this.options = Object.assign({}, defaultOptions, options);
this.history = [];
this.possibleAnswers = answers;
}
clear() {
this.history = [];
}
get results() {
let numberOfVotes = this.history.length,
votesResults = [];
Object.keys(this.possibleAnswers).forEach(answerId => {
let answerIdCounter = 0;
let voters = [];
this.history.forEach(vote => {
if (answerId == vote.id) {
answerIdCounter++;
voters.push(vote.name);
}
});
let percentOfAllVotes = answerIdCounter / numberOfVotes * 100;
let formatedPercent = isNaN(percentOfAllVotes) ?
0 :
parseFloat(percentOfAllVotes).
toFixed(3).
slice(0, -1);
votesResults.push({
votes: answerIdCounter,
voters: voters,
percent: formatedPercent });
});
return votesResults;
}
vote(answerId, name = "Anonymouse") {
if (this.possibleAnswers[answerId]) {
let getCurrentDate = new Date().toLocaleString();
this.history.push({ id: answerId, name: name, date: getCurrentDate });
return true;
} else throw new Error("Incorrect answer's id");
}}
// Plugin: https://codepen.io/badurski/pen/RJvJQZ
const q1 = new poll("Will Poland win the footboal match?", {
0: { title: "Yes" },
1: { title: "No" } });
// Add some randome votes
for (let i = 0; i < 20; i++) {
q1.vote(Math.floor(Math.random() * (1 - 0 + 1)) + 0);
}
// Poll interface script
let pollButtons = document.querySelectorAll('.poll-panel-btn'),
pollPanel = document.querySelector('.poll-panel');
pollButtons.forEach(button => {
button.onclick = () => {
if (button.getAttribute('disabled') != 'disabled') {
q1.vote(button.dataset.vote);
pollPanel.classList.add('poll-voted');
button.classList.add('--user-choice');
pollButtons.forEach(b => {
b.setAttribute('disabled', 'disabled');
let percent = q1.results[b.dataset.vote].percent + '%';
b.style.width = percent;
b.dataset.result = percent;
});
}
};
});
</script>

javascript requestAnimationFrame final position never exact

let pf = document.querySelectorAll('.pf');
for (let i of pf) {
Object.assign(i.style, {
left: '400px'
})
}
function shiftLetters() {
let start = performance.now();
let dist = -400;
let dur = 500;
const logoAnimate = (timestamp) => {
var runtime = timestamp - start
var progress = Math.min(runtime / dur, 1)
const position = progress * dist;
if (runtime < dur) {
for (let i = 0; i < pf.length; i++) {
(function(i) {
setTimeout(function() {
pf[i].style.transform = `translate3d(${position}px,0,0)`
}, 100 * i)
})(i);
}
requestAnimationFrame(logoAnimate)
}
}
requestAnimationFrame(logoAnimate)
}
document.getElementsByTagName('button')[0].addEventListener('click', shiftLetters);
#wrapper {
display: flex;
position: absolute;
-webkit-transform: translate(-50%, 10%);
transform: translate(-50%, 10%);
top: 50%;
left: 50%;
}
.pf {
display: inline-block;
position: relative;
width: 100px;
height: 100px;
margin: 2px;
background-color: red;
}
button {
display: block;
margin-top: 50px;
}
<div id="wrapper">
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
</div>
<button>animate</button>
I have 4 elements when button is clicked their supposed to end at the exact distance of the dist variable. Instead it end at random integers and never exactly -400px like stated in in my dist variable of -400. Has to be something simple. I've written the variables outside of scope etc etc..
The reason is that you never apply the final transform. On the last iteration of shiftLetters when position finally = -400 runtime is greater than dur so you never enter your if statement and apply the transform. Slightly refactored code below.
let pf = document.querySelectorAll('.pf');
for (let i of pf) {
Object.assign(i.style, {
left: '400px'
})
}
function shiftLetters() {
let start = performance.now();
let dist = -400;
let dur = 500;
const logoAnimate = (timestamp) => {
var runtime = timestamp - start
var progress = Math.min(runtime / dur, 1)
const position = progress * dist;
applyTransform(position);
if (runtime < dur) {
requestAnimationFrame(logoAnimate)
}
}
requestAnimationFrame(logoAnimate)
}
function applyTransform(position) {
for (let i = 0; i < pf.length; i++) {
setTimeout(function() {
pf[i].style.transform = `translate3d(${position}px,0,0)`
}, 100 * i)
}
}
document.getElementsByTagName('button')[0].addEventListener('click', shiftLetters);
#wrapper {
display: flex;
position: absolute;
-webkit-transform: translate(-50%, 10%);
transform: translate(-50%, 10%);
top: 50%;
left: 50%;
}
.pf {
display: inline-block;
position: relative;
width: 100px;
height: 100px;
margin: 2px;
background-color: red;
}
button {
display: block;
margin-top: 50px;
}
<div id="wrapper">
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
</div>
<button>animate</button>

Categories