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));
}
}
Related
So I'm making an Etch-a-Sketch with a range slider to change the grid size, but the slider keeps resetting to its default size (16x16) as soon as I move the mouse after changing the value (if I change the value and don't move the mouse, the size doesn't reset). For some reason this doesn't happen on Chrome: the value and grid size both change and stay that way until I change them again.
Here's the JSFiddle: https://jsfiddle.net/CamiCoding/7zpt14cs/
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Etch-a-Sketch</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="title">
<h1>Etch-a-Sketch</h1>
</div>
<div class="btns">
<button id="blackBtn">Black</button>
<button id="rainbowBtn">Rainbow</button>
<button id="colorBtn">Color</button>
<button id="eraserBtn">Eraser</button>
<button id="resetBtn">Reset</button>
<div class="colorPicker">
<input type="color" id="color" value="#000000">
<span>Pick a color</span>
</div>
<div class="sliderAndValue">
<input type="range" min="2" max="100" value="16" id="slider">
<p class="value">16</p>
</div>
</div>
<div class="grid">
</div>
<script src="script.js" defer></script>
</body>
</html>
CSS:
#font-face {
src: url("../fonts/sf-atarian-system.regular.ttf");
font-family: Atarian;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: Atarian;
background-color: #D1D1D1;
}
.title h1 {
font-size: 80px;
margin: 0px;
}
.btns {
display: flex;
flex-direction: row;
width: 700px;
height: 50px;
justify-content: space-evenly;
margin-top: 20px;
margin-bottom: 20px;
}
.btns button {
font-family: Atarian;
font-size: 24px;
height: 40px;
width: 80px;
border-radius: 5px;
transition: transform 0.2s ease-in-out;
}
.btns button:hover {
transform: scale(1.2);
}
.btns .active {
background-color: #505050;
color: white;
}
.colorPicker {
display: flex;
flex-direction: column;
align-items: center;
font-size: 20px;
}
.color span {
text-align: center;
}
#color {
width: 90px;
}
.sliderAndValue {
-webkit-appearance: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 24px;
}
#slider {
-webkit-appearance: none;
width: 150px;
height: 10px;
background: #000;
outline: none;
border: 4px solid gray;
border-radius: 4px;
}
/* for firefox */
#slider::-moz-range-thumb {
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
/* for chrome/safari */
#slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
.cell {
border: 1px solid black;
}
.cell.active {
background-color: black;
}
.grid {
display: inline-grid;
grid-template-columns: repeat(16, 2fr);
grid-template-rows: repeat(16, 2fr);
border: 5px solid gray;
border-radius: 5px;
height: 700px;
width: 700px;
background-color: white;
}
JS:
const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.getElementById('slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;
let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false
document.body.onmousedown = () => (mouseDown = true)
document.body.onmouseup = () => (mouseDown = false)
function setCurrentColor(newColor) {
currentColor = newColor;
}
function setCurrentMode(newMode) {
activateButton(newMode);
currentMode = newMode;
}
blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();
function createGrid() {
removeCells(grid);
let val = document.getElementById('slider').value;
sliderValue.textContent = val;
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for(let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
}
function activateButton(newMode) {
if (currentMode === 'rainbow') {
rainbowBtn.classList.remove('active');
} else if (currentMode === 'color') {
colorBtn.classList.remove('active');
} else if (currentMode === 'eraser') {
eraserBtn.classList.remove('active');
} else if (currentMode === 'black') {
blackBtn.classList.remove('active');
}
if (newMode === 'rainbow') {
rainbowBtn.classList.add('active');
} else if (newMode === 'color') {
colorBtn.classList.add('active');
} else if (newMode === 'eraser') {
eraserBtn.classList.add('active');
} else if (newMode === 'black') {
blackBtn.classList.add('active');
}
}
function changeColor(e) {
if (e.type === 'mouseover' && !mouseDown) return;
if (currentMode === 'rainbow') {
const randomR = Math.floor(Math.random() * 256);
const randomG = Math.floor(Math.random() * 256);
const randomB = Math.floor(Math.random() * 256);
e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
} else if (currentMode === 'color') {
e.target.style.backgroundColor = colorValue.value;
} else if (currentMode === 'eraser') {
e.target.style.backgroundColor = '#ffffff';
} else if (currentMode === 'black') {
e.target.style.background = '#000000';
}
}
slider.addEventListener('input', function(){
let val = document.getElementById('slider').value;
sliderValue.textContent = val;
removeCells(grid);
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for (let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
});
function removeCells(parent){
while(grid.firstChild){
grid.removeChild(grid.firstChild);
}
}
window.onload = () => {
createGrid(DEFAULT_SIZE);
activateButton(DEFAULT_MODE);
}
I do have another question regarding this same project, but about a different issue, please let me know if I should post a different question for it or if I should post it here too!
Thanks a lot in advance :).
I was able to track down the source of the issue, and fix it. Sounds weird, but document.body.onmousedown and document.body.onmouseup were creating the issue.
Replacing them with addEventListener seems to fix it.
I also removed some repeated code (in slider's input listener), by making maximum use of createGrid() function.
const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.querySelector('#slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;
let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false
document.body.addEventListener("mousedown", () => (mouseDown = true))
document.body.addEventListener("mouseup", () => (mouseDown = false))
function setCurrentColor(newColor) {
currentColor = newColor;
}
function setCurrentMode(newMode) {
activateButton(newMode);
currentMode = newMode;
}
blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();
function createGrid(val = 16) {
slider.value = val;
sliderValue.textContent = val;
removeCells(grid);
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for (let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
}
function activateButton(newMode) {
if (currentMode === 'rainbow') {
rainbowBtn.classList.remove('active');
} else if (currentMode === 'color') {
colorBtn.classList.remove('active');
} else if (currentMode === 'eraser') {
eraserBtn.classList.remove('active');
} else if (currentMode === 'black') {
blackBtn.classList.remove('active');
}
if (newMode === 'rainbow') {
rainbowBtn.classList.add('active');
} else if (newMode === 'color') {
colorBtn.classList.add('active');
} else if (newMode === 'eraser') {
eraserBtn.classList.add('active');
} else if (newMode === 'black') {
blackBtn.classList.add('active');
}
}
function changeColor(e) {
if (e.type === 'mouseover' && !mouseDown) return;
if (currentMode === 'rainbow') {
const randomR = Math.floor(Math.random() * 256);
const randomG = Math.floor(Math.random() * 256);
const randomB = Math.floor(Math.random() * 256);
e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
} else if (currentMode === 'color') {
e.target.style.backgroundColor = colorValue.value;
} else if (currentMode === 'eraser') {
e.target.style.backgroundColor = '#ffffff';
} else if (currentMode === 'black') {
e.target.style.background = '#000000';
}
}
slider.addEventListener('input', function(e) {
let val = parseInt(document.getElementById('slider').value);
createGrid(val);
});
function removeCells(parent) {
while (grid.firstChild) {
grid.removeChild(grid.firstChild);
}
}
window.onload = () => {
createGrid(DEFAULT_SIZE);
activateButton(DEFAULT_MODE);
}
#font-face {
src: url("../fonts/sf-atarian-system.regular.ttf");
font-family: Atarian;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: Atarian;
background-color: #D1D1D1;
}
.title h1 {
font-size: 80px;
margin: 0px;
}
.btns {
display: flex;
flex-direction: row;
width: 700px;
height: 50px;
justify-content: space-evenly;
margin-top: 20px;
margin-bottom: 20px;
}
.btns button {
font-family: Atarian;
font-size: 24px;
height: 40px;
width: 80px;
border-radius: 5px;
transition: transform 0.2s ease-in-out;
}
.btns button:hover {
transform: scale(1.2);
}
.btns .active {
background-color: #505050;
color: white;
}
.colorPicker {
display: flex;
flex-direction: column;
align-items: center;
font-size: 20px;
}
.color span {
text-align: center;
}
#color {
width: 90px;
}
.sliderAndValue {
-webkit-appearance: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 24px;
}
#slider {
-webkit-appearance: none;
width: 150px;
height: 10px;
background: #000;
outline: none;
border: 4px solid gray;
border-radius: 4px;
}
/* for firefox */
#slider::-moz-range-thumb {
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
/* for chrome/safari */
#slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
.cell {
border: 1px solid black;
}
.cell.active {
background-color: black;
}
.grid {
display: inline-grid;
grid-template-columns: repeat(16, 2fr);
grid-template-rows: repeat(16, 2fr);
border: 5px solid gray;
border-radius: 5px;
height: 700px;
width: 700px;
background-color: white;
user-select: none;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Etch-a-Sketch</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="title">
<h1>Etch-a-Sketch</h1>
</div>
<div class="btns">
<button id="blackBtn">Black</button>
<button id="rainbowBtn">Rainbow</button>
<button id="colorBtn">Color</button>
<button id="eraserBtn">Eraser</button>
<button id="resetBtn">Reset</button>
<div class="colorPicker">
<input type="color" id="color" value="#000000">
<span>Pick a color</span>
</div>
<div class="sliderAndValue">
<input type="range" min="2" value="16" id="slider">
<p class="value">16</p>
</div>
</div>
<div class="grid">
</div>
<script src="script.js" defer></script>
</body>
</html>
I need to add a click event to a css class so when clicked it switches to a different class. Specifically, I have a character class on li items that I would like to change to another class when the li item is clicked. Code:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link rel="stylesheet" href="app.css" />
</head>
<body>
<div class="container">
<h1>Client Search</h1>
<div id="searchWrapper">
<input
type="text"
name="searchBar"
id="searchBar"
placeholder="search for a character"
onkeyup="myFunction()"
/>
</div>
<ul id="charactersList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
css
body {
font-family: sans-serif;
background-color: #111d4a;
}
* {
box-sizing: border-box;
}
h1 {
color: #eee;
margin-bottom: 30px;
}
.container {
padding: 40px;
margin: 0 auto;
max-width: 1000px;
text-align: center;
}
#charactersList {
padding-inline-start: 0;
display: none;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
grid-gap: 20px;
}
.character {
list-style-type: none;
background-color: #eaeaea;
border-radius: 3px;
padding: 10px 20px;
display: grid;
grid-template-columns: 3fr 1fr;
grid-template-areas:
'name image'
'house image';
text-align: left;
}
.character:hover {
background-color: blue;
cursor: pointer;
}
.character > h2 {
grid-area: name;
margin-bottom: 0px;
}
.character > p {
grid-area: house;
margin: 0;
}
#searchBar {
width: 100%;
height: 32px;
border-radius: 3px;
border: 1px solid #eaeaea;
padding: 5px 10px;
font-size: 12px;
}
#searchWrapper {
position: relative;
}
#searchWrapper::after {
content: '🔍';
position: absolute;
top: 7px;
right: 15px;
}
javaScript
const charactersList = document.getElementById('charactersList');
const searchBar = document.getElementById('searchBar');
let clientNames = [];
searchBar.addEventListener('keyup', (e) => {
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clientNames.filter((character) => {
return (
character.name.toLowerCase().includes(searchString) ||
character.house.toLowerCase().includes(searchString)
);
});
displayCharacters(filteredCharacters);
});
const loadCharacters = async () => {
try {
const res = await fetch('https://hp-api.herokuapp.com/api/characters');
clientNames = await res.json();
displayCharacters(hpCharacters);
} catch (err) {
console.error(err);
}
};
const displayCharacters = (characters) => {
const htmlString = characters
.map((character) => {
return `
<li class="character">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
`;
})
.join('');
charactersList.innerHTML = htmlString;
};
loadCharacters();
//change the display of characterListfrom none to grid
function myFunction() {
var charactersList = document.getElementById("charactersList");
charactersList.style.display = "grid";
//also check if searchBar is empty and set display back to none
var searchBar = document.getElementById("searchBar").value;
if (searchBar === ""){
charactersList.style.display = "none";
}
}
Great question!
I just made a CodePen to illustrate how to programmatically change CSS class names when a li item is clicked. Check out this example and let me know if this clarifies the problem : )
JS
let list = document.getElementById('myList');
let items = ['First', 'Second', 'Third', 'Fourth', 'Fifth'];
for(let item of items){
let li = document.createElement("LI");
li.appendChild(document.createTextNode(item));
li.classList.add('blue');
li.addEventListener("click", () => {
li.classList.remove('blue');
li.classList.add('red');
});
list.appendChild(li);
}
HTML
<ul id="myList"></ul>
CSS
.blue{
color: blue;
}
.red{
color: red;
}
https://codepen.io/CrowlsYung/pen/eYJRPjx
Suggested Change
<li class="character" onclick="handleItemClick(event)">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
function handleItemClick(e){
e.currentTarget.classList.toggle('prevClass')
e.currentTarget.classList.toggle('newClass');
}
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.
I'm creating a currency converter app using html,css and javascript, and when text is entered into the <input> on the left, the converted value will appear in the input element on the right: <p id = "converted">.
I want to keep the underline(border-bottom) the same length on the <p id = "converted">. Currently, when you enter text into the input element on the left, the one on the right increases in size and makes the underline larger. I want the underline to stay the same as when there is no text in the element.
I am currently styling the <p id = "converted"> element like so:
padding-right: 40%;
border-bottom: 0.5vh solid white;
I do not think the API I am using will work correctly with the stack overflow snippets, but I will include a link to a codepen: https://codepen.io/oliknight/pen/XLvQow
let currlet currencyArr = [];
let ratesArr = [];
window.addEventListener("load", () => {
const api = "https://api.exchangeratesapi.io/latest?base=GBP";
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
for (currency in data.rates) {
currencyArr.push(currency);
ratesArr.push(data.rates[currency]);
// create 'option' element here
var optionLeft = document.createElement("option");
var optionRight = document.createElement("option");
optionLeft.textContent = currency;
optionRight.textContent = currency;
document.querySelector("#left-select").appendChild(optionLeft);
document.querySelector("#right-select").appendChild(optionRight);
}
document.querySelector("#input").addEventListener("keyup", convert);
function convert() {
const input = document.querySelector("#input");
let leftSelectValue = document.querySelector("#left-select").value;
let convertedNumber = document.querySelector("#converted");
for (let i = 0; i < currencyArr.length; i++) {
if (leftSelectValue === currencyArr[i]) {
convertedNumber.textContent = ratesArr[i].toFixed(4) * input.value;
}
}
}
});
});
encyArr = [];
let ratesArr = [];
window.addEventListener("load", () => {
const api = "https://api.exchangeratesapi.io/latest?base=GBP";
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
for (currency in data.rates) {
currencyArr.push(currency);
ratesArr.push(data.rates[currency]);
// create 'option' element here
var optionLeft = document.createElement("option");
var optionRight = document.createElement("option");
optionLeft.textContent = currency;
optionRight.textContent = currency;
document.querySelector("#left-select").appendChild(optionLeft);
document.querySelector("#right-select").appendChild(optionRight);
}
document.querySelector("#input").addEventListener("keyup", convert);
function convert() {
const input = document.querySelector("#input");
let leftSelectValue = document.querySelector("#left-select").value;
let convertedNumber = document.querySelector("#converted");
for (let i = 0; i < currencyArr.length; i++) {
if (leftSelectValue === currencyArr[i]) {
convertedNumber.textContent = ratesArr[i].toFixed(4) * input.value;
}
}
}
});
});
html {
font-family: "Lato", sans-serif;
font-weight: thin;
background-image: linear-gradient(to right top, #90d0ff, #008ef7);
color: white;
height: 100vh;
overflow: hidden;
}
h1 {
text-align: center;
font-size: 5em;
position: absolute;
left: 0;
right: 0;
margin: auto;
}
.container {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.container p {
font-size: 8em;
display: inline-block;
padding-right: 40%;
border-bottom: 0.5vh solid white;
max-width: 50%;
}
.parent {
display: flex;
justify-content: center;
height: 100vh;
align-items: center;
}
.container select {
background: transparent;
color: white;
padding: 20px;
width: 80px;
height: 60px;
border: none;
font-size: 20px;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5);
-webkit-appearance: button;
outline: none;
margin-left: 10%;
}
.original {
background: transparent;
border: none;
border-bottom: 0.5vh solid white;
font-size: 8em;
max-width: 50%;
outline: none;
font-family: "Lato", sans-serif;
font-weight: thin;
color: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Currency Converter</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="main.css" />
<link href="https://fonts.googleapis.com/css?family=Lato:300&display=swap" rel="stylesheet" />
</head>
<body>
<h1>Currency Converter</h1>
<div class="parent">
<div class="container">
<input type="text" class="original" id="input" />
<select id="left-select"> </select>
</div>
<div class="container" id="ctn">
<p id="converted">0</p>
<select id="right-select"> </select>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
Thanks!
If you replace max-width with width in your css, the percentage (e.g. 50%) width will stay the same, regardless of how long the converted number is. However this poses a problem regarding your overflow.
You could remove the padding, but you could still run into issues whereby only half a digit is showing at the end, depending on how big the device is:
So you may want to either reduce the font size or experiment with width percentages (maybe 49 or 51 .. ) , or both ..
If you knew exactly how many decimal digits there would be in the returned converted number, this would help determine an adequate size font.
Good luck, and hope this helps
I do my ToDo list. (I learn vanilla JS). And I have some problem with saving some items to localStorage. When I use Google chrome(F12), I see undefiend. Maybe, I do not save correctly to localStorage. I tried to change var task to array, but it does not help. Pleas, show me my mistakes. I know, my code must be rewritten, it is my first code on JS. P.s. in console (in stackOverflow) I have that error
{
"message": "Uncaught SyntaxError: Unexpected identifier",
"filename": "https://stacksnippets.net/js",
"lineno": 348,
"colno": 6
}
but in my browser not.
var task = document.querySelector("ul");
var forTask;
function toLocal(){
forTask = task.innerHTML;
localStorage.setItem("forLocal",forTask);
}
function newElement(newChild) {
let btnDel= document.createElement("button");
btnDel.className = "fa fa-trash-o";
let myEd = document.getElementById("myEdit");
let spanClose1 = document.getElementsByClassName("close1")[0];
let spanRedact = document.getElementsByClassName("redact")[0];
let myDel = document.getElementById("myDelete");
let spanClose = document.getElementsByClassName("close")[0];
let spanYes = document.getElementsByClassName("yes")[0];
//create button
let divWithBut = document.createElement("div");
divWithBut.className = "forButt";
let btnRedact = document.createElement("button");
btnRedact.className = "fa fa-pencil";
//redact but
btnRedact.onclick = function(){
myEd.style.display = "block";
let editText = document.getElementById("editText");
let divWithText = divWithBut.parentElement.getElementsByClassName("todoPost")[0];
editText.value = divWithText.innerHTML;
editText.currentTarget;
spanRedact.onclick = function(){
divWithText.textContent = editText.value;
divWithText.className = "todoPost";
myEd.style.display = "none";
};
spanClose1.onclick = function() {
myEd.style.display = "none";
};
}
/*************************** */
/*done but*/
let doneBut = document.createElement("button");
doneBut.className = "fa fa-check-circle-o";
doneBut.onclick = function(){
let divWithText = divWithBut.parentElement.getElementsByClassName("todoPost")[0];
divWithText.classList.toggle("checked");
}
/******************* */
divWithBut.appendChild(btnRedact);
divWithBut.appendChild(doneBut);
divWithBut.appendChild(btnDel);
/******************/
//for index
let indexDiv = document.createElement("div");
indexDiv.className = "indexDiv";
let numbInd = 1;
indexDiv.innerHTML = numbInd;
/*********************************** */
//create arrow
let divWithArrow = document.createElement("div");
divWithArrow.className = "myArrow";
let arrowUP = document.createElement("i");
arrowUP.className = "fa fa-chevron-up";
let arrowDown = document.createElement("i");
arrowDown.className = "fa fa-chevron-down";
divWithArrow.appendChild(arrowUP);
divWithArrow.appendChild(arrowDown);
//for date
let date = new Date();
let curr_date = date.getDate();
let curr_month = date.getMonth()+1;
let curr_year = date.getFullYear();
let curr_hour = date.getHours();
let curr_minutes = date.getMinutes();
let d = (curr_date + "." + curr_month + "." + curr_year+"<br>"+curr_hour+":"+curr_minutes);
let divTime = document.createElement("div");
divTime.style.textAlign = "center";;
divTime.innerHTML = d;
//***************************/
let div1 = document.createElement("div");
div1.className = "timeComent";
let myli = document.createElement("li");
myli.className = "todoPost";
let addField = document.getElementById("addField").value;
task = document.createTextNode(addField);
myli.appendChild(task);
div1.appendChild(divTime);
div1.appendChild(indexDiv);
div1.appendChild(divWithArrow);
div1.appendChild(myli);
divWithBut.style.display = "flex";
div1.appendChild(divWithBut);
if (addField === '') {
alert("You must write something!");
} else {
document.getElementById("forToDo").appendChild(div1);
toLocal();
}
document.getElementById("addField").value = "";
//delete but
btnDel.onclick = function(){
myDel.style.display = "block";
spanClose.onclick = function() {
myDel.style.display = "none";
};
spanYes.onclick = function() {
myDel.style.display = "none";
div1.remove();
};
}
toLocal();
}
if(localStorage.getItem("forLocal")){
task.innerHTML = localStorage.getItem("forLocal");
}
*{
margin: 0;
padding: 0;
}
header{
width: 100%;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
overflow: auto;
}
.firstBar{
width: 100%;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
overflow: auto;
}
.indexDiv{
font-style: normal;
text-align: center;
color: #fff;
width: 15px;
height: 20px;
margin: 10px;
background-color: #888;
}
.fafaArrow{
font-size: 24px;
color: #000;
}
.timeComent{
margin-top: 15px;
margin-bottom: 15px;
display: flex;
justify-content:center;
align-items: center;
}
.numberpost{
padding: 5px;
color: rgb(255, 255, 255);
background: rgb(141, 112, 112);
}
.todoPost{
background-color: #eee;
width: 50%;
margin: 5px;
overflow: auto;
text-align: justify;
}
.shadow {
background: rgba(102, 102, 102, 0.5);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
}
.window {
width: 300px;
height: 50px;
text-align: center;
padding: 15px;
border: 3px solid #0000cc;
border-radius: 10px;
color: #0000cc;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
background: #fff;
}
.shadow:target {display: block;}
.redact {
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.redact:hover {
background-color: #68f462;
color: white;}
.close{
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.close:hover{
background-color: #f44336;
color: white;
}
/* Style the close button */
.close3 {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.yes {
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.yes:hover{
background-color: #68f462;
color: white;
}
.close1{
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.close1:hover{
background-color: #f44336;
color: white;
}
/* When clicked on, add a background color and strike out text */
div li.checked {
background: #888;
color: #fff;
text-decoration: line-through;
}
/* Add a "checked" mark when clicked on */
div li.checked::before {
content: '';
position: absolute;
border-color: #fff;
border-style: solid;
border-width: 0 2px 2px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 15px;
width: 7px;
}
<!DOCTYPE html>
<html>
<head>
<title>TO DO List</title>
<link rel="stylesheet" type="text/css" href="styles/style.css" >
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<header>
<input id="addField" type="text" size="70%" placeholder="Task" name="Task">
<button type="button" onclick="newElement()">Add</button>
</header>
<div>
<div class="firstBar">
<div class="fafaArrow">
<i class="fa fa-caret-up" ></i>
<i class="fa fa-caret-down"></i>
<input class="inptxt" type="text" size="50%" name="Task">
<i class="fa fa-filter"></i>
</div>
</div>
</div>
<ul id="forToDo" >
</ul>
<div id="myDelete" class="shadow">
<div class="window">Delete item?<br>
<span class="yes">Yes</span>
<span class="close">No</span>
</div>
</div>
<div id="myEdit" class="shadow">
<div class="window">
Edit text?<br>
<label>
<textarea id="editText"></textarea>
</label>
<span class="redact">Save</span>
<span class="close1">Cancel</span>
</div>
</div>
<script src="js/script2.js"></script>
</body>
</html>
When you add an element to the page, at a certain point you do this
task = document.createTextNode(addField);
Since task is a global variable (you declared it at the top), you're overshadowing it with the TextNode you're creating, so that when you then call toLocal and you do
forTask = task.innerHTML;
task has no innerHTML attribute, so it returns undefined.
Also, for some reason, you call toLocal again at the end of newElement. It's not the problem but it's something you may want to think about. I'm not sure it's what you want.
#TakayashiHarano gave a couple of hints to solve this, but I'm not sure what you want is just to have the latest element in the local storage. So I would re-write toLocal so that it takes a string (the text of the item) as input, writes it at the end of a JSON array (already populated with what was in the local storage previously), and puts the array back in local storage.
function toLocal(toAdd) {
let storage = localStorage.getItem('forLocal');
if (storage === null) {
storage = [];
} else {
storage = JSON.parse(storage);
}
storage.push(toAdd);
localStorage.setItem('forLocal', JSON.stringify(storage));
}
Then you should modify the part of the code that reads the local storage (the one at the end) to basically simulate adding a new item as you would do when creating a new task, but for each item in the parsed JSON coming from local storage.
To be fair, your code needs a good dose of rewriting to achieve this, so I'll just leave you with this as an exercise.
The following changes are needed.
1 - Set up two variables separably for the following task variable.
var task = document.querySelector("ul");
task = document.createTextNode(addField);
For example, "ulElement" for the first one, and "task" for the second one.
This is to prevent to override the previously defined value.
2 - Move the timing for obtaining the ul element and load localStorage.
function onReady() {
ulElement = document.querySelector("ul");
if(localStorage.getItem("forLocal")){
ulElement.innerHTML = localStorage.getItem("forLocal");
}
}
window.addEventListener('DOMContentLoaded', onReady, true);
To ensure the element existence, document.querySelector() should be called after the DOMContentLoaded event fired.
https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event
3 - Delete toLocal(); in the end of the newElement() function.
As far as my testing code, there is no need this statement.