I'm practicing localStorage with a simple clicker game and have two "upgrade" elements which make the gameplay faster. When they are clicked they change a specific value from 0 to 1 and also change an element from visible to hidden.
When I "buy" an upgrade and then save the game and refresh the log, it is returning the values properly if I bought one upgrade (that upgrade's value is 1 and the other upgrade's value is still 0). However, even though they are logging two different values, my if statement which checks for a 0 value is still causing both of elements to get hidden when only one is bought.
I added CSS/HTML and cleared out the bits not needed. I don't know how to make a snippet work with localStorage but the results should be reproducible here.
//declare constants
const storage = window.localStorage;
const counter = document.getElementById("count");
const clicker = document.getElementById("clicker");
const savebtn = document.getElementById("savebtn");
const clearbtn = document.getElementById("clearbtn");
const auto = document.getElementById("auto");
const up1 = document.getElementById("up1");
const up2 = document.getElementById("up2");
let save = {};
var clickStrength = 1;
var passive = 0;
var up1done = 0;
var up2done = 0;
//check save
if (storage.getItem("save")) {
save = JSON.parse(storage.getItem("save"));
counter.innerHTML = "Gold: " + save.count;
clickStrength = JSON.parse(storage.getItem("clickStrength"));
passive= JSON.parse(storage.getItem("passive"));
//check upgrades
if (JSON.parse(storage.getItem("up1done") === 0)) {
up1.style.visibility = "visible";
} else {
up1.style.visibility = "hidden";
};
if (JSON.parse(storage.getItem("up2done") === 0)) {
up2.style.visibility = "visible";
} else {
up2.style.visibility = "hidden";
};
} else {
save.count = 0;
counter.innerHTML = "Gold: " + 0;
};
clicker.addEventListener("click", function() {
save.count = save.count + clickStrength;
counter.innerHTML = "Gold: " + save.count;
});
//save
savebtn.addEventListener("click", function() {
storage.setItem("save", JSON.stringify(save));
storage.setItem("clickStrength", JSON.stringify(clickStrength));
storage.setItem("passive", JSON.stringify(passive));
storage.setItem("up1done", JSON.stringify(up1done));
storage.setItem("up2done", JSON.stringify(up2done));
});
//clear
clearbtn.addEventListener("click", function () {
storage.clear();
});
//Upgrades
up1.addEventListener("click", function() {
clickStrength = clickStrength + 1;
up1.style.visibility = "hidden";
up1done = up1done + 1;
});
up2.addEventListener("click", function() {
passive = passive + 0.5;
up2.style.visibility = "hidden";
up2done = up2done + 1;
});
console.log(up1done);
console.log(up2done);
console.log(JSON.parse(storage.getItem("up1done")));
console.log(clickStrength);
console.log(JSON.parse(storage.getItem("up2done")));
#wrapper {
display: grid;
justify-content: center;
grid-template-columns: repeat(3, 1fr);
height: 98vh;
width: 100%;
grid-gap: 10px;
}
#savebar {
display: grid;
justify-content: center;
grid-template-columns: repeat(3, 1fr);
grid-column: 1/3;
grid-row: 1/2;
grid-gap: 10px;
}
.savebtn {
text-align: center;
height: 30%;
align-self: center;
border-radius: 8px;
cursor: pointer;
margin-bottom: 5vh;
color: white;
-webkit-box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
}
#savebtn {
background-color: green;
}
#clearbtn {
background-color: red;
}
#auto {
background-color: blue;
}
#gamespace {
grid-column: 1/3;
grid-row: 2/5;
}
#upgrades {
grid-column: 3/4;
grid-row: 1/5;
}
#upInfo {
text-align: center;
margin-top: 5vh;
font-size: 2.5em;
}
#upsWrap {
grid-gap: 5px;
display: grid;
grid-template-columns: repeat(2, 1fr);
}
.ups {
width: 90%;
cursor: pointer;
width: 100px;
height: 100px;
background-color: red;
}
.upsTool {
visibility: hidden;
position: absolute;
text-align: center;
background-color: darkGrey;
width: 10vw;
height: 5vh;
line-height: 5vh;
margin-left: 3.25vh;
font-size: .85em;
border-radius: 8px;
}
.ups:hover .upsTool {
visibility: visible;
}
<body>
<div id="wrapper">
<div id="savebar">
<span id="savebtn" class="savebtn">Save</span>
<span id="clearbtn" class="savebtn">Clear</span>
<span id="auto" class="savebtn"></span>
</div>
<div id="gamespace">
<div id="clicker">Click Me!</div>
<div id="count">Gold: 0</div>
</div>
<div id="upgrades">
<div id="upInfo">Upgrades!</div>
<div id="upsWrap">
<div id="up1" class="ups"><div id="up1Tool" class="upsTool">Click gold +1</div></div>
<div id="up2" class="ups"><div id="up2Tool" class="upsTool">Income +0.5</div></div>
</div>
</div>
</div>
</body>
You simply made a typo here:
if (JSON.parse(storage.getItem("up1done") === 0)) {
...
}
Take a look at the parentheses. It should be if (JSON.parse(storage.getItem("up1done")) === 0). You can run localStorage in JSFiddle. Try running it here.
//declare constants
const storage = window.localStorage;
const counter = document.getElementById("count");
const clicker = document.getElementById("clicker");
const savebtn = document.getElementById("savebtn");
const clearbtn = document.getElementById("clearbtn");
const auto = document.getElementById("auto");
const up1 = document.getElementById("up1");
const up2 = document.getElementById("up2");
let save = {};
var clickStrength = 1;
var passive = 0;
var up1done = 0;
var up2done = 0;
//check save
if (storage.getItem("save")) {
save = JSON.parse(storage.getItem("save"));
counter.innerHTML = "Gold: " + save.count;
clickStrength = JSON.parse(storage.getItem("clickStrength"));
passive= JSON.parse(storage.getItem("passive"));
//check upgrades
if (JSON.parse(storage.getItem("up1done")) === 0) {
up1.style.visibility = "visible";
} else {
up1.style.visibility = "hidden";
};
if (JSON.parse(storage.getItem("up2done")) === 0) {
up2.style.visibility = "visible";
} else {
up2.style.visibility = "hidden";
};
} else {
save.count = 0;
counter.innerHTML = "Gold: " + 0;
};
clicker.addEventListener("click", function() {
save.count = save.count + clickStrength;
counter.innerHTML = "Gold: " + save.count;
});
//save
savebtn.addEventListener("click", function() {
storage.setItem("save", JSON.stringify(save));
storage.setItem("clickStrength", JSON.stringify(clickStrength));
storage.setItem("passive", JSON.stringify(passive));
storage.setItem("up1done", JSON.stringify(up1done));
storage.setItem("up2done", JSON.stringify(up2done));
});
//clear
clearbtn.addEventListener("click", function () {
storage.clear();
});
//Upgrades
up1.addEventListener("click", function() {
clickStrength = clickStrength + 1;
up1.style.visibility = "hidden";
up1done = up1done + 1;
});
up2.addEventListener("click", function() {
passive = passive + 0.5;
up2.style.visibility = "hidden";
up2done = up2done + 1;
});
console.log(up1done);
console.log(up2done);
console.log(JSON.parse(storage.getItem("up1done")));
console.log(clickStrength);
console.log(JSON.parse(storage.getItem("up2done")));
#wrapper {
display: grid;
justify-content: center;
grid-template-columns: repeat(3, 1fr);
height: 98vh;
width: 100%;
grid-gap: 10px;
}
#savebar {
display: grid;
justify-content: center;
grid-template-columns: repeat(3, 1fr);
grid-column: 1/3;
grid-row: 1/2;
grid-gap: 10px;
}
.savebtn {
text-align: center;
height: 30%;
align-self: center;
border-radius: 8px;
cursor: pointer;
margin-bottom: 5vh;
color: white;
-webkit-box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
box-shadow: 1px 3px 10px 0px rgba(0,0,0,0.75);
}
#savebtn {
background-color: green;
}
#clearbtn {
background-color: red;
}
#auto {
background-color: blue;
}
#gamespace {
grid-column: 1/3;
grid-row: 2/5;
}
#upgrades {
grid-column: 3/4;
grid-row: 1/5;
}
#upInfo {
text-align: center;
margin-top: 5vh;
font-size: 2.5em;
}
#upsWrap {
grid-gap: 5px;
display: grid;
grid-template-columns: repeat(2, 1fr);
}
.ups {
width: 90%;
cursor: pointer;
width: 100px;
height: 100px;
background-color: red;
}
.upsTool {
visibility: hidden;
position: absolute;
text-align: center;
background-color: darkGrey;
width: 10vw;
height: 5vh;
line-height: 5vh;
margin-left: 3.25vh;
font-size: .85em;
border-radius: 8px;
}
.ups:hover .upsTool {
visibility: visible;
}
<body>
<div id="wrapper">
<div id="savebar">
<span id="savebtn" class="savebtn">Save</span>
<span id="clearbtn" class="savebtn">Clear</span>
<span id="auto" class="savebtn"></span>
</div>
<div id="gamespace">
<div id="clicker">Click Me!</div>
<div id="count">Gold: 0</div>
</div>
<div id="upgrades">
<div id="upInfo">Upgrades!</div>
<div id="upsWrap">
<div id="up1" class="ups"><div id="up1Tool" class="upsTool">Click gold +1</div></div>
<div id="up2" class="ups"><div id="up2Tool" class="upsTool">Income +0.5</div></div>
</div>
</div>
</div>
</body>
Although unrelated to what you're asking, I think that it is your not intention to set the variables up1done and up2done to 0 every time the game is rerun. This makes the two buttons reappear when rerunning the second time after saving the first time.
Related
I created a simple carousel using HTML, CSS, and Javascript.
Clicking the left button shows the previous slide and the right one shows the next slide.
But my concern is that slide change is not working correctly
when clicking the next button: After the final slide, it won't go to the first slide again.
when clicking the previous button: After the first slide, it won't go again to last the slide again.
So please review my code and let me know my error.
let right = document.querySelector('.nxt');
let left = document.querySelector('.pre');
let slids = document.querySelector('.slids');
let first = document.querySelector('.first');
let scond = document.querySelector('.scond');
let third = document.querySelector('.third');
let fouth = document.querySelector('.fouth');
let slidesArray=[first,scond,third,fouth];
let index= 0;
let activeSlide= slidesArray[index].classList.add('active');
left.addEventListener('click',()=>{
if (++index > 0) {
slidesArray[index].classList.add('active');
}
});
right.addEventListener('click',()=>{
if (index > 0) {
slidesArray[index].classList.add('deactive');
slidesArray[--index].classList.add('active');
}
});
body{
display: flex;
justify-content: center;
align-items: center;
}
.slids>*{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50% ,-50%);
width: 400px;
height: 350px;
font-size: 50px;
font-weight: 600;
display: grid;
place-items: center;
border-radius: 20px;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
visibility: hidden;
}
.active{
visibility: visible;
}
.first{
background-color: #F7EC09;
}
.scond{
background-color: #3EC70B;
}
.third{
background-color: #3B44F6;
}
.fouth{
background-color: #A149FA;
}
.btn{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50% ,-50%);
display: flex;
gap: 450px;
}
.nxt, .pre{
font-size: 100px;
font-weight: 700;
background: none;
border: none;
cursor: pointer;
}
<body>
<div class="slids">
<div class="first">1</div>
<div class="scond">2</div>
<div class="third">3</div>
<div class="fouth">4</div>
</div>
<div class="btn">
<button class="nxt"><</button>
<button class="pre">></button>
</div>
A chained ternary expression can be used to determine the new index number in a single line:
to = to >= size ? 0 : to < 0 ? size - 1 : to;
Details are commented in example
// Reference the buttons
let next = document.querySelector('.next');
let prev = document.querySelector('.prev');
/*
Collect all div.slide into an array
Define the array's size
Define a number value outside of the function
*/
let slides = [...document.querySelectorAll('.slide')];
let size = slides.length;
let index = 0;
// Bind click event to button.prev
prev.onclick = event => move(index - 1);
// Bind click event to button.next
next.onclick = event => move(index + 1);
/*
Pass newest index number
Ternary expression:
If the given number is greater than or equal to size of the array...
...return 0...
...If the given number is less than 0...
...return last index of array...
...otherwise return the given number
Toggle the current .slide.active and new .slide
Assign index as the given number
*/
function move(to) {
to = to >= size ? 0 : to < 0 ? size - 1 : to;
slides[index].classList.toggle("active");
slides[to].classList.toggle("active");
index = to;
}
html {
font: 300 3vmin/1 Consolas;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
main {
display: flex;
justify-content: center;
align-items: center;
position: relative;
max-width: max-content;
min-height: 100vh;
}
.slides {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 420px;
height: 400px;
overflow: hidden;
}
.slide {
display: grid;
place-items: center;
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 350px;
border-radius: 20px;
font-size: 50px;
font-weight: 600;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
visibility: hidden;
transform: translate(-50%, -50%);
}
.active {
visibility: visible;
}
.slide:first-of-type {
background-color: #F7EC09;
}
.slide:nth-of-type(2) {
background-color: #3EC70B;
}
.slide:nth-of-type(3) {
background-color: #3B44F6;
}
.slide:nth-of-type(4) {
background-color: #A149FA;
}
.ctrl {
display: flex;
justify-content: space-between;
position: absolute;
top: 45%;
left: 45%;
width: 150%;
transform: translate(-50%, -50%);
}
.next,
.prev {
border: none;
font-size: 100px;
font-weight: 700;
background: none;
cursor: pointer;
}
<main>
<section class="slides">
<div class="slide active">1</div>
<div class="slide">2</div>
<div class="slide">3</div>
<div class="slide">4</div>
</section>
<menu class="ctrl">
<button class="prev"><</button>
<button class="next">></button>
</menu>
</main>
You need to reset the index of the slide when you click next and reach to maximum slide you need to reset index to 0 to return to first slide, also when you click prev and you in the first slide, you need to reset index to 3 to return the last slide.
let right = document.querySelector(".nxt");
let left = document.querySelector(".pre");
let slids = document.querySelector(".slids");
let first = document.querySelector(".first");
let scond = document.querySelector(".scond");
let third = document.querySelector(".third");
let fouth = document.querySelector(".fouth");
const elementsArr = [first, scond, third, fouth];
let slidesArray = [first, scond, third, fouth];
let index = 0;
let activeSlide = slidesArray[index].classList.add("active");
left.addEventListener("click", () => {
if (index === 3) {
index = -1;
}
index++;
resetActiveElements()
});
right.addEventListener("click", () => {
if (index === 0) index = 4;
index--;
resetActiveElements()
});
const resetActiveElements = () => {
elementsArr.forEach((element, i) => {
if (index === i) {
element.classList.add("active");
} else {
element.classList.remove("active");
}
});
}
body{
display: flex;
justify-content: center;
align-items: center;
}
.slids>*{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50% ,-50%);
width: 400px;
height: 350px;
font-size: 50px;
font-weight: 600;
display: grid;
place-items: center;
border-radius: 20px;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
visibility: hidden;
}
.active{
visibility: visible;
}
.first{
background-color: #F7EC09;
}
.scond{
background-color: #3EC70B;
}
.third{
background-color: #3B44F6;
}
.fouth{
background-color: #A149FA;
}
.btn{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50% ,-50%);
display: flex;
gap: 450px;
}
.nxt, .pre{
font-size: 100px;
font-weight: 700;
background: none;
border: none;
cursor: pointer;
}
<body>
<div class="slids">
<div class="first">1</div>
<div class="scond">2</div>
<div class="third">3</div>
<div class="fouth">4</div>
</div>
<div class="btn">
<button class="nxt"><</button>
<button class="pre">></button>
</div>
/* <div class="btn">
<button class="pre"><</button>
<button class="nxt">></button>
</div> */
let right = document.querySelector('.nxt');
let left = document.querySelector('.pre');
let slids = document.querySelector('.slids');
let first = document.querySelector('.first');
let scond = document.querySelector('.scond');
let third = document.querySelector('.third');
let fouth = document.querySelector('.fouth');
let slidesArray = [first, scond, third, fouth];
let index = 0;
let activeSlide = slidesArray[index].classList.add('active');
left.addEventListener('click', () => {
slidesArray[index].classList.remove('active');
if (index == 0) {
index = 3;
slidesArray[index].classList.add('active');
} else {
index--;
slidesArray[index].classList.add('active');
}
});
right.addEventListener('click', () => {
slidesArray[index].classList.remove('active');
if (index == 3) {
index = 0;
slidesArray[index].classList.add('active');
} else {
index++;
slidesArray[index].classList.add('active');
}
});
I am trying to get this card slider to transform cards on each click. Every time the user clicks on any of the cards, the last card in the array goes to the beginning, and all cards are moving as in a carousel, scaling and changing their zIndex. It works perfectly on the first click but then cards start translating differently.
After searching and searching, I read you have to keep track of translations therefore I am using distanceCounter0Elm and distanceCounterElse variables, but it does not seem to work. Also tried to reset all transforms and even a different approach by adding css classes but could not get it to work properly.
Where is my mistake? It might be something very simple but I am not being able to see it. I would really appreciate your help. Many thanks!
<section class="section" id="portfolio">
<h3 class="tituloTrabajos">Nuestros trabajos</h3>
<div class="container" id="grasscoContainer"></div>
</section>
section{
background-color: #021845;
width: 98vw;
height: 180vh;
padding-top: 10vh;
display: flex;
flex-direction: column;
}
.tituloTrabajos{
color: white;
text-align: center;
font-size: 2vw;
margin-bottom: 25vh;
}
.sitesContainer{
display: flex;
justify-content: space-evenly;
align-items: center;
align-content: center;
flex-wrap: wrap;
row-gap: 8vh;
}
.siteDiv{
background-color: #ddf1fc;
}
.sitePic{
width: 38vw;
border-radius: 20px;
}
.container{
position: relative;
height: 150vh;
width: 98vw;
display: flex;
justify-content: center;
overflow: hidden;
}
.eachCard{
width: 38vw;
height: 40vh;
border-radius: 20px;
box-shadow: -5px 0 6px #000, 10px 0 6px #000;
transition: 0.4s ease-out;
position: relative;
border: 5px solid white;
cursor: pointer;
top: 5vh;
}
.eachCard:not(:first-child){
margin-left: -30vw;
}
.originalzIndex2{
z-index: 2;
}
.originalzIndex1{
z-index: 1;
}
.originalScale{
transform: scale(1.2);
}
var grasscoImgs = ["img/grassco2.png", "img/grassco3.png", "img/grassco.png", "img/grassco4.png", "img/grassco6.png"];
var grasscoContainer = document.getElementById("grasscoContainer");
var cards = document.getElementsByClassName("eachCard");
grasscoImgs.forEach(function(image){
var img = document.createElement("img");
img.src = image;
img.classList.add("eachCard");
grasscoContainer.appendChild(img);
img.onclick = slideCards;
});
cards[2].classList.add("originalzIndex2", "originalScale");
cards[3].classList.add("originalzIndex1");
var cardsArr = Array.from(cards);
function slideCards(){
var lastCard = cardsArr.pop();
cardsArr.splice(0, 0, lastCard);
var distanceCounter0Elm = " translate(-32vw)";
var distanceCounterElse = " translate(2vw)";
for (let i = 0; i < cardsArr.length; i++){
if (i == 0){
cardsArr[0].style.transform = distanceCounter0Elm + " scale(0.8)";
cardsArr[0].style.zIndex = "0";
distanceCounter0Elm += " translate(-32vw)";
} else {
cardsArr[1].style.transform = distanceCounterElse + " scale(1)";
cardsArr[2].style.transform = distanceCounterElse + " scale(1.2)";
cardsArr[3].style.transform = distanceCounterElse + " scale(1)";
cardsArr[4].style.transform = distanceCounterElse + " scale(0.8)";
cardsArr[1].style.zIndex = "1";
cardsArr[2].style.zIndex = "2";
cardsArr[3].style.zIndex = "1";
cardsArr[4].style.zIndex = "0";
distanceCounterElse += " translate(2vw)";
};
};
};
So I am making an advent calendar, and have already made the layout and made it possible to open the doors. But how do I set it to open on a specific date? I am pretty new to coding so I do not know where to start.
I have an index.html file
an css file and a java file
const kalenderKnap = document.querySelector(".btn-start");
const kalenderContainer = document.querySelector(".container");
const kalenderDage = 24;
const åbenLåge = (path, event) => {
event.target.parentNode.style.backgroundImage = `url(${path})`;
event.target.style.opacity = "0";
event.target.style.backgroundColor = "lightblue";
}
const startKalender = () => {
for(let i = 0; i < kalenderDage; i++) {
const kalenderLåge = document.createElement("div");
const kalenderLågeTekst = document.createElement("div");
kalenderLåge.classList.add("image");
kalenderLåge.style.gridArea = "låge" + (i +1);
kalenderContainer.appendChild(kalenderLåge);
kalenderLågeTekst.classList.add("text");
kalenderLågeTekst.innerHTML = i + 1;
kalenderLåge.appendChild(kalenderLågeTekst);
lågeNummer = i + 1;
let coursePath = `./filer/låge${lågeNummer}.jpg`;
kalenderLågeTekst.addEventListener("click", åbenLåge.bind(null, coursePath));
}
}
kalenderKnap.addEventListener("click", startKalender);
* {
box-sizing: border-box;
}
.btn-start {
background-color: darkred;
color: white;
border: 2px solid black;
border-radius: 15px;
margin: 15px auto;
display: block;
width: 10rem;
height: 2rem;
}
.container {
width: 800px;
height: 900px;
border: 5px solid black;
margin: 15px auto;
background-image: url("./filer/baggrund1.jpg");
background-size: cover;
display: grid;
grid-template-columns: repeat(4, 25%);
grid-template-rows: repeat(6, 1fr);
grid-template-areas:
"låge7 låge8 låge2 låge6"
"låge3 låge13 låge5 låge23"
"låge17 låge21 låge19 låge14"
"låge24 låge4 låge9 låge12"
"låge10 låge15 låge1 låge18"
"låge16 låge20 låge11 låge22";
}
.image {
background-image: none;
background-size: cover;
background-position: center;
}
.text {
height: 100%;
width: 100%;
color: solid black;
padding: 10px;
border: 2px solid black;
transition: opacity 2s;
}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<title>Julekalender</title>
</head>
<body>
<button class="btn-start">Start Julekalender</button>
<div class="container">
</div>
<script src="main.js"></script>
</div>
</body>
</html>
so how do i make each door open on the specific date, and where do i put it?
You can do this with the Date-Object. Just add this to your åbenLåge-Function:
const åbenLåge = (path, event) => {
var date = new Date();
if(date.getDate() == event.target.innerHTML) {
...
}
}
This checks if the selected number corresponds to today's date. So for example today you only can click on the door with number 7.
Here is the edited fiddle:
const kalenderKnap = document.querySelector(".btn-start");
const kalenderContainer = document.querySelector(".container");
const kalenderDage = 24;
const åbenLåge = (path, event) => {
var date = new Date();
if(date.getDate() == event.target.innerHTML) {
event.target.parentNode.style.backgroundImage = `url(${path})`;
event.target.style.opacity = "0";
event.target.style.backgroundColor = "lightblue";
}
}
const startKalender = () => {
for(let i = 0; i < kalenderDage; i++) {
const kalenderLåge = document.createElement("div");
const kalenderLågeTekst = document.createElement("div");
kalenderLåge.classList.add("image");
kalenderLåge.style.gridArea = "låge" + (i +1);
kalenderContainer.appendChild(kalenderLåge);
kalenderLågeTekst.classList.add("text");
kalenderLågeTekst.innerHTML = i + 1;
kalenderLåge.appendChild(kalenderLågeTekst);
lågeNummer = i + 1;
let coursePath = `./filer/låge${lågeNummer}.jpg`;
kalenderLågeTekst.addEventListener("click", åbenLåge.bind(null, coursePath));
}
}
kalenderKnap.addEventListener("click", startKalender);
* {
box-sizing: border-box;
}
.btn-start {
background-color: darkred;
color: white;
border: 2px solid black;
border-radius: 15px;
margin: 15px auto;
display: block;
width: 10rem;
height: 2rem;
}
.container {
width: 800px;
height: 900px;
border: 5px solid black;
margin: 15px auto;
background-image: url("./filer/baggrund1.jpg");
background-size: cover;
display: grid;
grid-template-columns: repeat(4, 25%);
grid-template-rows: repeat(6, 1fr);
grid-template-areas:
"låge7 låge8 låge2 låge6"
"låge3 låge13 låge5 låge23"
"låge17 låge21 låge19 låge14"
"låge24 låge4 låge9 låge12"
"låge10 låge15 låge1 låge18"
"låge16 låge20 låge11 låge22";
}
.image {
background-image: none;
background-size: cover;
background-position: center;
}
.text {
height: 100%;
width: 100%;
color: solid black;
padding: 10px;
border: 2px solid black;
transition: opacity 2s;
}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<title>Julekalender</title>
</head>
<body>
<button class="btn-start">Start Julekalender</button>
<div class="container">
</div>
<script src="main.js"></script>
</div>
</body>
</html>
You can pass an object as a parameter like this:
const åbenLåge = (kalenderLågeTekst, event) => {
var date = new Date();
if(date.getDate() == kalenderLågeTekst.day) {
...
}
}
const startKalender = () => {
for(let i = 0; i < kalenderDage; i++) {
....
kalenderLågeTekst.path = coursePath;
kalenderLågeTekst.day = lågeNummer;
kalenderLågeTekst.addEventListener("click", åbenLåge.bind(null, kalenderLågeTekst));
}
}
I am working on a WordPress site and I have a snippet of html that iterates with repeating classes.
I am attempting to create a click function but only affect the element that is clicked. All in JavaScript.
As of right now my function is affecting all elements with the class name. Test code can be found at my CodePen or below.
I can accomplish this without nested loops as seen here. So my assumption is the problem lies within the second forEach loop. I would appreciate any light on the matter.
Thank you in advance.
/**
*Constructors
**/
const carousel = document.getElementsByClassName("carousel");
const btns = document.getElementsByClassName("btns");
/**
*Execute
**/
Array.from(btns).forEach((i) => {
i.addEventListener("click", (e) => {
Array.from(carousel).forEach((n) => {
if (i.classList.contains("slide-left")) {
n.scrollLeft -= 20;
} else if (i.classList.contains("slide-right")) {
n.scrollLeft += 20;
} else {
alert("ut oh");
}
});
});
});
/*
**Utilities
*/
/*containers*/
.feed-container {
position: absolute;
height: 200px;
width: 100%;
display: grid;
grid-template-columns: 1;
grid-template-rows: 1;
}
.carousel {
grid-row: 1;
grid-column: 1/5;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 1;
grid-gap: 15px;
align-self: center;
border: 1px solid #ccc;
overflow-x: scroll;
overflow-y: hidden;
}
/*div-buttons*/
div[class*="slide-"] {
/*opacity: 0;*/
position: sticky;
grid-row: 1;
z-index: 5;
place-self: center;
transition: 0.5s;
padding: 15px;
}
.slide-left {
grid-column: 1;
}
.slide-right {
grid-column: 4;
}
/*items*/
div[class*="item-"] {
grid-row: 1;
width: 400px;
height: 200px;
}
.item-1 {
background: blue;
}
.item-2 {
background: red;
}
.item-3 {
background: grey;
}
.item-4 {
background: yellow;
}
/*scrollbar*/
::-webkit-scrollbar {
display: none;
}
/*chevrons*/
[class*="chevron-"] {
box-sizing: border-box;
position: relative;
display: block;
transform: scale(var(--ggs, 1));
width: 22px;
height: 22px;
border: 2px solid transparent;
border-radius: 25px;
}
[class*="chevron-"]::after {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
width: 40px;
height: 40px;
border-bottom: 8px solid;
border-left: 8px solid;
bottom: 0;
}
.chevron-left::after {
transform: rotate(45deg);
left: 15px;
}
.chevron-right::after {
transform: rotate(-135deg);
right: 15px;
}
/*
**Exceptions
*/
.btns:hover {
cursor: pointer;
}
.opaque {
opacity: 1 !important;
}
.show {
display: block;
}
<div id="wrapper" style="display:grid; grid-template-rows:repeat(2, auto); grid-gap: 100px;">
<div>
<h1>Header</h1>
<div class="feed-container">
<div class="carousel">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
</div>
<div class="slide-left btns">
<div class="chevron-left"></div>
</div>
<div class="slide-right btns">
<div class="chevron-right"></div>
</div>
</div>
</div>
<br>
<div>
<h1>Header</h1>
<div class="feed-container">
<div class="carousel">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
</div>
<div class="slide-left btns">
<div class="chevron-left"></div>
</div>
<div class="slide-right btns">
<div class="chevron-right"></div>
</div>
</div>
</div>
</div>
It's because you're getting all the elements with class name carousel and then looping through them with each click.
const carousel = document.getElementsByClassName("carousel");
Instead what you need to do is get the carousels only under the button's parent when you trigger the click event
eg something like this:
Array.from(btns).forEach((i) => {
i.addEventListener("click", (e) => {
const targetElement = e?.target || e?.srcElement;
const parent = targetElement.parentElement();
const carousel = Array.from(parent.getElementsByClassName("carousel"));
carousel.forEach((n) => {
if (i.classList.contains("slide-left")) {
n.scrollLeft -= 20;
} else if (i.classList.contains("slide-right")) {
n.scrollLeft += 20;
} else {
alert("ut oh");
}
});
});
});
I took a look at the following as recommend and it seems to do the trick.
I created a variable that calls the parentNode "forEach()" button clicked. Oppose to looping through each element.
Working example, codePen
const carousel = document.querySelectorAll(".carousel");
const btns = document.querySelectorAll(".btns");
btns.forEach((i) => {
i.addEventListener("click", () => {
var x = i.parentNode;
var y = Array.from(x.querySelectorAll(".carousel"));
y.forEach((n) => {
if (i.classList.contains("slide-left")) {
n.scrollLeft -= 20;
} else {
n.scrollLeft += 20;
}
});
});
});
I have an input field that add task. when i add the task a delete button appear next to each task
these task are stored in the local storage as an array
when i click delete button i want to delete the specific item not all the local storage
in general we use localStorage.removeItem(key);
let inputTask = document.querySelector('.input');
let tasks = document.querySelector('.tasks');
let add = document.querySelector('.add');
let alls = [];
//show tasks
function show() {
if (window.localStorage.task) {
let storedTaskes = JSON.parse(localStorage.getItem("task"));
storedTaskes.forEach((item) => {
let paragraph = document.createElement('p');
let deleteBtn = document.createElement('button');
deleteBtn.className = "delete";
deleteBtn.innerHTML = "Delete";
deleteBtn.id = item;
deleteBtn.setAttribute("onclick","deleteBtn(this)");
console.log(deleteBtn.value);
paragraph.innerHTML = item;
paragraph.appendChild(deleteBtn);
tasks.appendChild(paragraph);
});
}
}
// add tasks
add.onclick = function () {
if (inputTask.value.trim() !== "") {
alls.push(inputTask.value);
for (let i = 0; i < alls.length; i++) {
window.localStorage.setItem(`task`, JSON.stringify(alls));
}
}
inputTask.value = '';
show();
}
show();
//Delete Task
function deleteBtn(ob) {
let id = ob.id;
let taskArray = JSON.parse(localStorage.getItem("task"));
for(let i = 0; i < taskArray.length; i++){
if(taskArray[i] === id){
localStorage.removeItem(taskArray[i]);
}
}
}
body{
height: 90vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
}
.form {
background-color: #f0f0f0;
padding: 20px;
width: 500px;
text-align: center;
display: flex;
align-item: center;
justify-content: center;
gap: 15px;
}
.input{
border: 0;
outline: none;
padding: 10px 20px;
width: 300px;
border-radius: 5px;
}
.add,
.delete{
border: 0;
outline: none;
background-color: red;
color: white;
padding: 10px;
border-radius: 5px;
cursor: pointer;
}
.tasks {
background-color: #f0f0f0;
padding: 20px;
width: 500px;
}
p {
display: block;
background-color: white;
padding: 15px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="container">
<div class="form">
<input type="text" class="input">
<input type="submit" class="add" value="Add Task">
</div>
<div class="tasks"></div>
</div>
How can i delete the specific item from the array in the local storage and show the new result for the user
You need to remove from the array and store the array again since that is how your other part works
function deleteBtn(ob) {
let id = ob.id;
let taskArray = JSON.parse(localStorage.getItem("task"));
taskArray = taskArray.filter(item => item != id)
localStorage.setItem("task", JSON.stringify(taskArray));
show()
}
ALso change
for (let i = 0; i < alls.length; i++) {
window.localStorage.setItem(`task`, JSON.stringify(alls));
}
to
localStorage.setItem(`task`, JSON.stringify(alls));
Here is a better version
I use delegation for the delete and save to localstorage without reading it again
I use a generated ID as id
Note I have to comment out the localstorage part since SO does not allow it
let inputTask = document.querySelector('.input');
let tasks = document.querySelector('.tasks');
let add = document.querySelector('.add');
let storedTasks // = localStorage.getItem("task"); // uncomment on your server
let allTasks = storedTasks ? JSON.parse(storedTasks) : [];
function show() {
tasks.innerHTML = allTasks
.map(task => `<p>${task.input} <button class="delete" data-id="${task.id}">X</button></p>`)
.join('<br/>');
}
// add tasks
add.onclick = function() {
const input = inputTask.value.trim();
if (input !== "") {
const id = allTasks.length; // use the length at this time
allTasks.push({ id:new Date().getTime(), input });
// localStorage.setItem("task",JSON.stringify(allTasks)); // uncomment on your server
inputTask.value = '';
show();
}
};
show();
document.querySelector(".tasks").addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("delete")) {
let id = tgt.dataset.id;
allTasks = allTasks.filter(item => item.id != id)
tgt.closest("p").remove();
// localStorage.setItem("task",JSON.stringify(allTasks)); // uncomment on your server
}
});
body {
height: 90vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
}
.form {
background-color: #f0f0f0;
padding: 20px;
width: 500px;
text-align: center;
display: flex;
align-item: center;
justify-content: center;
gap: 15px;
}
.input {
border: 0;
outline: none;
padding: 10px 20px;
width: 300px;
border-radius: 5px;
}
.add,
.delete {
border: 0;
outline: none;
background-color: red;
color: white;
padding: 10px;
border-radius: 5px;
cursor: pointer;
}
.tasks {
background-color: #f0f0f0;
padding: 20px;
width: 500px;
}
p {
display: block;
background-color: white;
padding: 15px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="container">
<div class="form">
<input type="text" class="input">
<input type="submit" class="add" value="Add Task">
</div>
<div class="tasks"></div>
</div>
function deleteBtn({id}) {
let taskArray = JSON.parse(localStorage.getItem("task")); // get the array
taskArray = taskArray.filter(ob=> ob.id != id ) // remove the id
localStorage.setItem("task", JSON.stringify(taskArray));
show()
}
but since you are using tasks.appendChild(paragraph)
you will have to change show function to
//show tasks
function show() {
if (window.localStorage.task) {
let storedTaskes = JSON.parse(localStorage.getItem("task"));
tasks.innerHTML = "" // here
storedTaskes.forEach((item) => {
let paragraph = document.createElement('p');
let deleteBtn = document.createElement('button');
deleteBtn.className = "delete";
deleteBtn.innerHTML = "Delete";
deleteBtn.id = item;
deleteBtn.setAttribute("onclick","deleteBtn(this)");
console.log(deleteBtn.value);
paragraph.innerHTML = item;
paragraph.appendChild(deleteBtn);
tasks.appendChild(paragraph)
});
}
}