I'm trying to make a simple countup timer with a start/stop button. I don't understand why the while loop crashes the page even though it has a 1sec delay. Is there a easier way to keep updating the time until I press the button?
let startButton = document.getElementById("btn-start-stop");
let timerOutput = document.getElementById("timer");
let runTimer = false;
let sec = 0;
let startTimer = false;
console.log(startTimer);
startButton.onclick = function () {
startTimer = !startTimer;
while (startTimer) {
setInterval(function () {
console.log(sec);
}, 1000);
}
};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="an exercise to manipulate DOM-elements">
<meta name="author" content="lars berg">
<meta name="keywords" content="a template for at exercise">
<link rel="stylesheet" type="text/css" href="css/style.css">
<title>DOM | Manipulate</title>
<script src="https://kit.fontawesome.com/fa41e523cd.js" crossorigin="anonymous"></script>
<script src="scripts/script.js" defer></script>
</head>
<body>
<header>
<h1>DOM | Manipulation</h1>
</header>
<main>
<div class="flex-container">
<div class="counter-container">
<h2 class="h2-counter">How long time will it take to read this information?</h2>
<div id="timer">
00:00:00
</div>
<div class="buttons">
<button id="btn-start-stop" type="button">
<i class="fa-solid fa-play fa-2x"></i>
</button>
<button id="btn-reset" type="button">
<i class="fa-solid fa-arrow-rotate-left fa-2x"></i>
</button>
</div>
</div>
</div>
</main>
<footer>
</footer>
</body>
</html>
You should not use a while() loop as this will block the thread.
Use setInterval() to preform an action at a specific interval (1000ms), and use clearInterval() to stop it on second press
Regarding the seconds to HMS, I'ved used this SO one-liner and made a function of it that will be called after we've bumped the seconds.
let startButton = document.getElementById("btn-start-stop");
let timerOutput = document.getElementById("timer");
let sec = 0;
let timer = null;
startButton.onclick = function () {
if (timer) {
clearInterval(timer);
timer = null;
} else {
timer = setInterval(() => ++sec && update(), 1000);
}
};
function update() {
timerOutput.innerHTML = new Date(sec * 1000).toISOString().substr(11, 8);
}
<script src="https://kit.fontawesome.com/fa41e523cd.js" crossorigin="anonymous"></script>
<header>
<h1>DOM | Manipulation</h1>
</header>
<main>
<div class="flex-container">
<div class="counter-container">
<h2 class="h2-counter">How long time will it take to read this information?</h2>
<div id="timer">
00:00:00
</div>
<div class="buttons">
<button id="btn-start-stop" type="button">
<i class="fa-solid fa-play fa-2x"></i>
</button>
<button id="btn-reset" type="button">
<i class="fa-solid fa-arrow-rotate-left fa-2x"></i>
</button>
</div>
</div>
</div>
</main>
While loop will block your thread because JavaScript is single threaded language.
let startButton = document.getElementById("btn-start-stop");
let timerOutput = document.getElementById("timer");
let runTimer = false;
let sec = 0;
let startTimer = false;
console.log(startTimer);
startButton.onclick = function () {
// you can change your button here
setInterval(function () {
console.log(sec);
sec = sec+1
// implement your logic here for seconds
}, 1000);
};
Because while looping, you are generating a call stack of setTimeout again and again which seems to crash the browser stack
check below sample code while no loop just use recursive approach
let startButton = document.getElementById("btn-start-stop");
let timerOutput = document.getElementById("timer");
let runTimer = false;
let sec = 0;
let startTimer = false;
let clearTime
let count = 0
startButton.onclick = function () {
clearTime = setTimeout("startWatch( )", 1000)
};
function startWatch(){
setInterval(function () {
console.log(count);
count++
}, 1000);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="an exercise to manipulate DOM-elements">
<meta name="author" content="lars berg">
<meta name="keywords" content="a template for at exercise">
<link rel="stylesheet" type="text/css" href="css/style.css">
<title>DOM | Manipulate</title>
<script src="https://kit.fontawesome.com/fa41e523cd.js" crossorigin="anonymous"></script>
<script src="scripts/script.js" defer></script>
</head>
<body>
<header>
<h1>DOM | Manipulation</h1>
</header>
<main>
<div class="flex-container">
<div class="counter-container">
<h2 class="h2-counter">How long time will it take to read this information?</h2>
<div id="timer">
00:00:00
</div>
<div class="buttons">
<button id="btn-start-stop" type="button">
<i class="fa-solid fa-play fa-2x"></i>
</button>
<button id="btn-reset" type="button">
<i class="fa-solid fa-arrow-rotate-left fa-2x"></i>
</button>
</div>
</div>
</div>
</main>
<footer>
</footer>
</body>
</html>
Related
so I'm trying to make an app that displays the cpu usage, ram usage, gpu usage and disk usage to a bar graph. I'm at the point where I can display the total percent of ram used but I am not able to update the value in real time and show it to the bar graph. Any help would be greatly appreciated.
Code
dashboard.js
const os = require("os");
const fs = require("fs");
const { memoryUsage } = require("process");
const os_free_mem = os.freemem()
let free_mem = (Math.round(os_free_mem / (1024*1024)))
const os_total_mem = os.totalmem()
let total_mem = (Math.round(os_total_mem / (1024*1024)))
const cpu_usage = document.querySelector(".cpu_usage");
const ram_usage = document.querySelector(".ram_usage");
const gpu_usage = document.querySelector(".gpu_usage");
const disk_usage = document.querySelector(".disk_usage");
const free_mem_lbl = document.getElementById("mem")
const total_mem_lbl = document.getElementById("tmem")
// FUNCTIONS
function update_cpu_usage(cpu_usage, value) {
value = Math.round(value);
cpu_usage.querySelector(".cpu_usage_fill").style.width = `${value}%`;
}
function update_ram_usage(ram_usage, value) {
value = Math.round(value);
ram_usage.querySelector(".ram_usage_fill").style.width = `${value}%`;
}
function update_gpu_usage(gpu_usage, value) {
value = Math.round(value);
gpu_usage.querySelector(".gpu_usage_fill").style.width = `${value}%`;
}
function update_disk_usage(disk_usage, value) {
value = Math.round(value);
disk_usage.querySelector(".disk_usage_fill").style.width = `${value}%`;
}
function find_cpu_percent() {
var free_mem_percent = Math.round((free_mem / total_mem ) * 100);
free_mem_lbl.innerText = `${free_mem_percent}`
}
find_cpu_percent();
tmem.innerText = `${total_mem}`
update_cpu_usage(cpu_usage, 55);
update_ram_usage(ram_usage, free_mem_percent);
update_gpu_usage(gpu_usage, 24);
update_disk_usage(disk_usage, 75)
dashboard.html
<!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>Dashboard</title>
<link rel="stylesheet" href="css/dashboard.css">
<script src="https://kit.fontawesome.com/e637815e35.js" crossorigin="anonymous"></script>
<script type="module" src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.js"></script>
</head>
<body>
<div class="main">
<div class="sidebar">
<ul>
<li><ion-icon name="home-sharp"></ion-icon></li>
<li><ion-icon name="speedometer-outline"></ion-icon></li>
<li><i class="fas fa-clock-rotate-left"></i></li>
<li><i class="fa-brands fa-usb"></i></li>
</ul>
</div>
<div class="main-content">
<h3>System Information</h3>
<!-- Usage Bars -->
<span class="cpu_text">CPU</span>
<div class="cpu_usage">
<div class="cpu_usage_fill"></div>
</div>
<span class="ram_text">RAM</span>
<div class="ram_usage">
<div class="ram_usage_fill"></div>
</div>
<span class="gpu_text">GPU</span>
<div class="gpu_usage">
<div class="gpu_usage_fill"></div>
</div>
<span class="disk_text">DISK</span>
<div class="disk_usage">
<div class="disk_usage_fill"></div>
</div>
<!-- System Specifications -->
<div class="specs">
<h3>System Specifications</h3>
<h5>CPU</h5>
<p class="info" id="cpu_name">CPU : </p>
<p class="info" id="cpu_speed">Speed :</p>
<p class="info" id="cpu_cores">Cores : </p>
<p id="mem" style="margin-left: 200px; font-size:40px"></p>
<p id="tmem" style="margin-left: 200px; font-size:40px"></p>
</div>
<script src="js/dashboard.js"></script>
</div>
</body>
</html>
I am making a simple ToDo app that when you write in the input form and submit it, it posts it neatly in a flex-box design below.
After it adds Your writing to the ToDo list at the bottom, JavaScript clears the input selection box.
My problem is that all the created ToDo list items are the SAME! They have the same class name and structure. I do not know how to handle all the buttons that are created so that when you click on the <button class='delete-btn'>x</button> it deletes only that button.
I have put all the writing templates created into a simple array called arrayOfText.
I was hoping I could delete the specific <div class='todo-div'>...</div> that the button was clicked from and then rewrite the whole .innerHTML of the ToDo list section.
This basically updates it and removes the div from the ToDo list that the button was clicked from, but I cannot seem to get it to work.
If you need more information, please message me.
"use strict";
const outputSection = document.querySelector("#output-section");
outputSection.innerHTML = "";
const writingArea = document.querySelector("#writing-area");
const publishBtn = document.querySelector(".default-btn");
const deleteBtns = document.getElementsByClassName("delete-btn");
const allToDoDivs = document.getElementsByClassName("todo-div");
const arrayOfText = [];
const cutAndPrintFunc = function (e) {
e.preventDefault();
//take writing in and print it to the current agenda
// clear the writing area
if (writingArea.value != "") {
const date = new Date();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDay()).padStart(2, "0");
const year = date.getFullYear();
const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
const AMorPM = date.getHours() > 12 ? "PM" : "AM";
const minute = String(date.getMinutes()).padStart(2, "0");
const template = `
<div class="todo-div">
<h1 class="text-content">${writingArea.value}</h1>
<button class="delete-btn">x</button>
<p class="date-p">${month}/${day}/${year} --- requested # ${hour}:${minute} ${AMorPM} </p>
</div>`;
arrayOfText.push(template);
outputSection.insertAdjacentHTML("beforeend", template);
writingArea.value = "";
Array.from(allToDoDivs).forEach((el, ind) => {
if (ind % 2 === 0) {
el.style.backgroundColor = "#3ce815";
el.lastElementChild.style.color = "black";
}
//-----this does not work
// Array.from(allToDoDivs)[
// allToDoDivs.length - 1
// ].children[1].addEventListener("click", () => {
// console.log(this);
// // arrayOfText.pop(this);
// // outputSection.innerHTML = arrayOfText.join("");
// });
});
}
};
//publish text by hitting enter or pressing the plus sign in textbox
publishBtn.addEventListener("click", cutAndPrintFunc);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/style.css" type="text/css" />
<title>Griffin's ToDo List</title>
</head>
<body>
<header>
<h1>
Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do
List
</h1>
<div id="mini-flex-div">
<div class="ball" id="blue"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="purple"> </div>
<p>What needs to be done today...</p>
<div class="ball" id="purple"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="blue"> </div>
</div>
</header>
<main>
<div id="writer-div">
<form>
<input
id="writing-area"
type="text"
rows="1"
placeholder="Lets get this out of the way..."
maxlength="50"
spellcheck="true"
autofocus
></input>
<button class='default-btn'>+</button>
</form>
</div>
</main>
<div id="bottom-header">
<h1 id="output-h1">The current agenda...<hr id="splitter"></h1>
</div>
<section id="output-section">
<div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div>
<div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div>
</section>
<script src="/toDo.js"></script>
</body>
</html>
There are really only rare cases where you want to manipulate the DOM through HTML. So using insertAdjacentHTML and innerHTML is most of the time not what you want to do.
Use createElement, appendChild and removeChild instead.
For the delete button, you can use event delegation, and find the todo div that corresponds to the button using closest.
Alternating coloring per row can be done with a CSS rule.
Using all this you will have a code like that:
"use strict";
const outputSection = document.querySelector("#output-section");
outputSection.innerHTML = "";
const writingArea = document.querySelector("#writing-area");
const publishBtn = document.querySelector(".default-btn");
const cutAndPrintFunc = function(e) {
e.preventDefault();
//take writing in and print it to the current agenda
// clear the writing area
if (writingArea.value != "") {
const date = new Date();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDay()).padStart(2, "0");
const year = date.getFullYear();
const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
const AMorPM = date.getHours() > 12 ? "PM" : "AM";
const minute = String(date.getMinutes()).padStart(2, "0");
// create an actual div element using createElement
const todoItem = document.createElement('div')
// add the todo-div class to it
todoItem.classList.add('todo-div')
// here you can use innerHTML, but you still might want to
// avoid its usage in general
todoItem.innerHTML = `
<h1 class="text-content">${writingArea.value}</h1>
<button class="delete-btn">x</button>
<p class="date-p">${month}/${day}/${year} --- requested # ${hour}:${minute} ${AMorPM} </p>
`;
// append the created div element to the outputSection
outputSection.appendChild(todoItem);
writingArea.value = "";
}
};
//publish text by hitting enter or pressing the plus sign in textbox
publishBtn.addEventListener("click", cutAndPrintFunc);
// we attach an event listener on outputSection for click
outputSection.addEventListener("click", (evt) => {
// only handle the click if it happend on the delete button
if (evt.target.matches('.delete-btn')) {
evt.preventDefault();
// At this point the evt.target is the delete button the
// click happened on so you need search for the
// ascendant that represents the todo-div using closest
// and remove that element from outputSection
outputSection.removeChild(evt.target.closest('.todo-div'))
}
})
/* use the odd rule to style all odd todo-div elements */
.todo-div:nth-child(odd) {
background-color: #3ce815;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/style.css" type="text/css" />
<title>Griffin's ToDo List</title>
</head>
<body>
<header>
<h1>
Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do List
</h1>
<div id="mini-flex-div">
<div class="ball" id="blue"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="purple"> </div>
<p>What needs to be done today...</p>
<div class="ball" id="purple"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="blue"> </div>
</div>
</header>
<main>
<div id="writer-div">
<form>
<input id="writing-area" type="text" rows="1" placeholder="Lets get this out of the way..." maxlength="50" spellcheck="true" autofocus>
<button class='default-btn'>+</button>
</form>
</div>
</main>
<div id="bottom-header">
<h1 id="output-h1">The current agenda...
<hr id="splitter">
</h1>
</div>
<section id="output-section">
<div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div>
<div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div>
</section>
<script src="/toDo.js"></script>
</body>
</html>
Unrelated to your problem:
input elements do not have a closing tag </input>
If you simply wish to remove the item from the list, start at the clicked button, use parentNode to find the "grand" parent (parent's parent) element, and remove, removeChild, the button's parent element:
// get all buttons and add a click event listener
document.querySelectorAll("button.delete-btn").forEach(btn => btn.addEventListener("click",
evt => {
// get the button's "grandparent", and remove the parent
evt.target.parentNode.parentNode.removeChild(evt.target.parentNode);
}
))
<!-- SAMPLE TO DO LIST -->
<section id="output-section">
<div class="todo-div" style="background-color: rgb(60, 232, 21);">
<h1 class="text-content">abc</h1>
<button class="delete-btn">x</button>
<p class="date-p" style="color: black;">06/00/2022 --- requested # 7:49 AM </p>
</div>
<div class="todo-div">
<h1 class="text-content">def</h1>
<button class="delete-btn">x</button>
<p class="date-p">06/00/2022 --- requested # 7:49 AM </p>
</div>
<div class="todo-div" style="background-color: rgb(60, 232, 21);">
<h1 class="text-content">ghi</h1>
<button class="delete-btn">x</button>
<p class="date-p" style="color: black;">06/00/2022 --- requested # 7:49 AM </p>
</div>
</section>
here is some improvements in your html and js file.
we provide each inserted div an id based on arrayOfText length so we can direct access id and used it with combine todo-div + id
and remove particular div from its own parent.
"use strict";
const outputSection = document.querySelector("#output-section");
outputSection.innerHTML = "";
const writingArea = document.querySelector("#writing-area");
const publishBtn = document.querySelector(".default-btn");
const deleteBtns = document.getElementsByClassName("delete-btn");
const allToDoDivs = document.getElementsByClassName("todo");
const arrayOfText = [];
const cutAndPrintFunc = function (e) {
e.preventDefault();
//take writing in and print it to the current agenda
// clear the writing area
if (writingArea.value != "") {
const date = new Date();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDay()).padStart(2, "0");
const year = date.getFullYear();
const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
const AMorPM = date.getHours() > 12 ? "PM" : "AM";
const minute = String(date.getMinutes()).padStart(2, "0");
const indexAdd = (arrayOfText.length === 0) ? 0 : arrayOfText.length;
const template = `
<div class="todo todo-div${indexAdd}">
<h1 class="text-content">${writingArea.value}</h1>
<button class="delete-btn" onclick="removeTodoDiv(${indexAdd})">x</button>
<p class="date-p">${month}/${day}/${year} --- requested # ${hour}:${minute} ${AMorPM} </p>
</div>`;
arrayOfText.push(template);
outputSection.insertAdjacentHTML("beforeend", template);
writingArea.value = "";
Array.from(allToDoDivs).forEach((el, ind) => {
if (ind % 2 === 0) {
el.style.backgroundColor = "#3ce815";
el.lastElementChild.style.color = "black";
}
//-----this does not work
// Array.from(allToDoDivs)[
// allToDoDivs.length - 1
// ].children[1].addEventListener("click", () => {
// console.log(this);
// // arrayOfText.pop(this);
// // outputSection.innerHTML = arrayOfText.join("");
// });
});
}
};
//publish text by hitting enter or pressing the plus sign in textbox
publishBtn.addEventListener("click", cutAndPrintFunc);
function removeTodoDiv(index) {
const findDiv = document.getElementsByClassName('todo-div' + index)[0];
findDiv.parentNode.removeChild(findDiv);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/style.css" type="text/css" />
<title>Griffin's ToDo List</title>
</head>
<body>
<header>
<h1>
Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do
List
</h1>
<div id="mini-flex-div">
<div class="ball" id="blue"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="purple"> </div>
<p>What needs to be done today...</p>
<div class="ball" id="purple"> </div>
<div class="ball" id="orange"> </div>
<div class="ball" id="blue"> </div>
</div>
</header>
<main>
<div id="writer-div">
<form>
<input id="writing-area" type="text" rows="1" placeholder="Lets get this out of the way..." maxlength="50"
spellcheck="true" autofocus></input>
<button class='default-btn'>+</button>
</form>
</div>
</main>
<div id="bottom-header">
<h1 id="output-h1">The current agenda...
<hr id="splitter">
</h1>
</div>
<section id="output-section">
<!-- <div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div>
<div class="todo-div">
<h1 class="text-content">Mow the lawn</h1>
<button class="delete-btn">x</button>
<p class="date-p">mm/dd/yyyy</p>
</div> -->
</section>
<script src="./index.js"></script>
</body>
</html>
I fetch data, make it an object and print it's properties. I then need to update sensor.value - if readonly is false - with the press of a button, making it go from true to false and viceversa. How can I do it?
index.html
<head>
<link rel="stylesheet" href="style.css" />
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0" />
<title>Sensors</title>
</head>
<body>
<h1>Sensors</h1>
<div class="container" id="container"> </div>
<script src="sensor.js"></script>
<script src="script.js"></script>
</body>
script.js
const container = document.getElementById("container");
// api url
const api_url =
"https://hf3xzw.deta.dev/";
// Defining async function
fetch(api_url)
.then((r) => r.json()) // (1)
.then((body) => {
for (let index = 0; index < 8; index++) {
const sensor = JSONToSensor(body["sensors"][index]);
let newCard = document.createElement("div");
newCard.classList.add("card");
newCard.innerHTML = `<br>
<h2><span style="font-weight: normal;">Description: </span>${sensor.description}</h2>
<h2><span style="font-weight: normal;">ID: </span>${sensor.id}</h2>
<h2><span style="font-weight: normal;">Lat: </span>${sensor.lat}</h2>
<h2><span style="font-weight: normal;">Lng: </span>${sensor.lng}</h2>
<h2><span style="font-weight: normal;">Place: </span>${sensor.place}</h2>
<h2><span style="font-weight: normal;">Read Only: </span>${sensor.readonly}</h2>
<h2><span style="font-weight: normal;">State Code: </span>${sensor.state_code}</h2>
<h2><span style="font-weight: normal;">Value: </span>${sensor.value}</h2>
`;
container.appendChild(newCard);
}
});
Edit: forgot to rewrite the attempts I made to make it work.
First attempt
<button type="button" onclick="document.getElementById('container').innerHTML = 'Hey There'">Try it</button>
Second attempt
if (sensor.readonly == false) {
let btn = document.createElement("button");
btn.innerHTML = "Change value";
btn.onclick = function () {
change();
}
container.appendChild(btn);
}
function change() {
if (sensor.value == true)
sensor.value == false;
else
sensor.value == true;
container.appendChild(newCard);
}
I've seen something similar to this and tried to implement but I don't really understand what I'm doing
I'm a JS beginner and I'm trying to create a personal project, but I have some problems with implementing a toggle like button for multiples pictures.
below u can see my button but is working only to one photo. how can a create a loop for the same button to work on every picture that a have in my project? Please help me!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<script src="index.js" defer></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<button class="like__btn">
<span id="icon"><i class="far fa-thumbs-up"></i></span>
<span id="count">0</span> Like
</button>
</body>
</html>
JS:
const likeBtn = document.querySelector(".like__btn");
let likeIcon = document.querySelector("#icon");
count = document.querySelector("#count");
let clicked = false;
likeBtn.addEventListener("click", () => {
if (!clicked) {
clicked = true;
likeIcon.innerHTML = `<i class="fas fa-thumbs-up"></i>`;
count.textContent++;
} else {
clicked = false;
likeIcon.innerHTML = `<i class="far fa-thumbs-up"></i>`;
count.textContent--;
}
});
You need to use class instead of id attribute for span tags and then
get all buttons by querySelectorAll then create a loop and attach click event to those buttons.
Here is working sample:
const likeBtn = document.querySelectorAll(".like__btn");
likeBtn.forEach(function (item) {
item.addEventListener("click", (event) => {
let likeIcon = item.querySelector(".icon");
let count = item.querySelector(".count");
if (+count.textContent == 0) {
clicked = true;
likeIcon.innerHTML = `<i class="fas fa-thumbs-up"></i>`;
count.textContent++;
} else {
clicked = false;
likeIcon.innerHTML = `<i class="far fa-thumbs-up"></i>`;
count.textContent--;
}
});
})
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" />
<button class="like__btn">
<span class="icon"><i class="far fa-thumbs-up"></i></span>
<span class="count">0</span> Like
</button>
<button class="like__btn">
<span class="icon"><i class="far fa-thumbs-up"></i></span>
<span class="count">0</span> Like
</button>
<button class="like__btn">
<span class="icon"><i class="far fa-thumbs-up"></i></span>
<span class="count">0</span> Like
</button>
Yesterday I did countdown timer using JS, but there's 2 problems, console viewing "daysEl is null" in 18 and 30 line, and "redeclaration of const daysEl" in first line. Honestly I don't know what I did wrong. Here's the code:
const daysEl = document.getElementById("days");
const hoursEl = document.getElementById("hours");
const minsEl = document.getElementById("mins");
const secondsEl = document.getElementById("seconds");
const webStart = "1 Oct 2021";
function countdown() {
const webStartDate = new Date(webStart);
const currentDate = new Date();
const totalSeconds = (webStartDate - currentDate) / 1000;
const days = Math.floor(totalSeconds / 3600);
const hours = Math.floor(totalSeconds / 3600) % 24;
const mins = Math.floor(totalSeconds / 60) % 60;
const seconds = Math.floor(totalSeconds) % 60;
daysEl.innerHTML = days;
hoursEl.innerHTML = formatTime(hours);
minsEl.innerHTML = formatTime(mins);
secondsEl.innerHTML = formatTime(seconds);
}
function formatTime(time) {
return time < 10 ? '0${time}' : time;
}
// initial call
countdown();
setInterval(countdown, 1000);
and here's the structure of the website. It's not fully my code, I'm still refactoring it to look and work good:
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Comtatible" concent="IE=edge, chrome=1"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Strona poświęcona mojoj działalnośći w świecie fotografii. Od kilku lat moją pasją i życiem codziennym jest fotografia i na tej stronie chciał bym się nią podzielić z większym gronem odbiorców"/>
<meta name="keywords" content="pasja, fotografia, zdjęcia, portret, obiektyw, aparat"/>
<title>Patryk Śpiewak Fotografia</title>
<link rel="stylesheet" href="main.css" type="text/css">
<link rel="stylesheet" href="style/toggle.css" type="text/css">
<link rel="stylesheet" href="style/animate.css" type="text/css">
<link rel="stylesheet" href="style/studio.css" type="text/css">
<link rel="Shortcut icon" href="img/iko.png" />
<link href="https://fonts.googleapis.com/css?family=Gafata|Italianno|Roboto" rel="stylesheet">
<link rel="stylesheet" href="css/fontello.css" type="text/css">
<meta name="author" content="Dawid Girtler">
<link href="jquery.tabSlideOut.css" rel="stylesheet">
</head>
<body oncontextmenu="return false" onload="zmienslajd()">
<main>
<header>
<div class="hide">
<div id="toggle">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
<div id="menu">
<nav class="mobile">
<li>Portfolio
<ul>
<li>Sesje prywatne</li>
<li>Imprezy okolicznościowe</li>
<li>Uroczystości kościelne</li>
</ul>
</li>
<li>Usługi</li>
<li>Studio</li>
<li>Kontakt</li>
<li>O mnie</li>
</nav>
<div class="center">
<a href="https://www.facebook.com/PatrykSpiewakFotografia/" target="_blank" class="tilelink">
<div class="mediaiko"><i class="icon-facebook"></i></div></a>
<a href="https://www.youtube.com/channel/UChbk9ccRM0TDEV_MhoKqhUQ/featured" target="_blank" class="tilelink">
<div class="mediaiko"><i class="icon-youtube"></i></div></a>
<a href="https://www.instagram.com/patrykspiewakfotografia/" target="_blank" class="tilelink">
<div class="mediaiko"><i class="icon-instagram"></i></div></a>
<a href="https://www.messenger.com/t/PatrykSpiewakFotografia?fbclid=IwAR13JuU_-8_Xmq22w2usPNNXGmnRf03cp7GmcEN0FvoOh2IZJ8hO4_actGI" target="_blank" class="tilelink">
<div class="mediaiko"><i class="icon-comment-empty"></i></div></a>
<a href="pobierz.php" class="tilelink">
<div class="mediaiko"><i class="icon-download" style="color: black"></i></div>
</a>
</div>
</div>
</div>
<nav>
<div class="logo"><img src="img/home.png" /></div>
<div id="menuc">
<ul id="menutest">
<li onclick ="myFunction()">Portfolio</li>
<li>Usługi</li>
<li>Studio</li>
<li>Kontakt</li>
<li>O mnie</li>
</ul>
<ul id="menup" class="animated zoomin">
<li>Sesje prywatne</li>
<li>Imprezy okolicznościowe</li>
<li>Uroczystości kościelne</li>
</ul>
</div>
<div class="social">
<div class="iko">
<a href="https://www.facebook.com/PatrykSpiewakFotografia/" target="_blank" class="tilelink">
<i class="icon-facebook"></i>
</a>
<a href="https://www.instagram.com/patrykspiewakfotografia/" target="_blank" class="tilelink">
<i class="icon-instagram"></i>
</a>
<a href="https://www.youtube.com/channel/UChbk9ccRM0TDEV_MhoKqhUQ/featured" target="_blank" class="tilelink">
<i class="icon-youtube"></i>
</a>
<a href="https://www.messenger.com/t/PatrykSpiewakFotografia" target="_blank" class="tilelink">
<i class="icon-comment-empty"></i>
</a>
<a href="pobierz.php" class="tilelink">
<i class="icon-download" style="color: black"></i>
</a>
</div>
</div>
<!--Temporary-->
<div class="text">
<span>Już niedługo... 😊</span>
</div>
<div class="countdown-container">
<div class="countdown-el days-c">
<p class="big-text" id="hours">0</p>
<span>Dni</span>
</div>
<div class="countdown-el hours-c">
<p class="big-text" id="hours">0</p>
<span>Godzin</span>
</div>
<div class="countdown-el minutes-c">
<p class="big-text" id="hours">0</p>
<span>Minut</span>
</div>
<div class="countdown-el seconds-c">
<p class="big-text" id="hours">0</p>
<span>Sekund</span>
</div>
</div>
<!--Temporary-->
</nav>
</header>
</main>
<script src="jquery-3.2.1.min.js"></script>
<script>
function myFunction(x) {
x.classList.toggle("change");
}
</script>
<script src="jquery-3.2.1.min.js"></script>
<script>
$("#toggle").click(function() {
$(this).toggleClass("on");
$("#menu").slideToggle();
});
</script>
<script>
function myFunction() {
document.getElementById("menup").style.display = "block";
}
</script>
<script>
$(document).ready(function () {
$("li").click(function (evt) {
if(evt.target.tagName != 'LI')
return;
$("ul", this).toggle();
});
});
</script>
<script type="text/javascript" src="script.js" defer></script>
</body>
</html>
#Adam Saar's suggestion was to EITHER move the tag to the bottom of the page OR add the defer attribute. I have just created two files:
HTML:
<!DOCTYPE html>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<html>
<head>
<title>Countdown clock</title>
<script type="text/javascript" src="script.js" defer>
</script>
<style type="text/css">
</style>
</head>
<body>
<span id="days"></span> days <span id="hours"></span> hours <span id="mins"></span> minutes and <span id="seconds"></span> seconds
</body>
</html>
and "script.js" is:
const daysEl = document.getElementById("days");
const hoursEl = document.getElementById("hours");
const minsEl = document.getElementById("mins");
const secondsEl = document.getElementById("seconds");
const webStart = "1 Oct 2021";
function countdown() {
const webStartDate = new Date(webStart);
var currentDate = new Date();
const totalSeconds = (webStartDate - currentDate) / 1000;
const days = Math.floor(totalSeconds / (3600 * 24)); // updated to gets days
const hours = Math.floor(totalSeconds / 3600) % 24;
const mins = Math.floor(totalSeconds / 60) % 60;
const seconds = Math.floor(totalSeconds) % 60;
daysEl.innerHTML = days;
hoursEl.innerHTML = formatTime(hours);
minsEl.innerHTML = formatTime(mins);
secondsEl.innerHTML = formatTime(seconds);
}
function formatTime(time) {
return time < 10 ? `0${time}` : time; // updated to use backticks instead of quotes
}
// initial call
countdown();
setInterval(countdown, 1000);
And, this works as I would expect. I have updated two lines of the script - to get days rather than hours for your "days" element and to use backticks instead of quotes for the template string in formatTime().
So, it is the location of the script that was causing the problem - if you keep it in the head tag and use the defer attribute as I have done, it works ok.
you defined the ids wrong in the HTML you should change it like so:
<div class="countdown-container">
<div class="countdown-el days-c">
<p class="big-text" id="days">0</p>
<span>Dni</span>
</div>
<div class="countdown-el hours-c">
<p class="big-text" id="hours">0</p>
<span>Godzin</span>
</div>
<div class="countdown-el minutes-c">
<p class="big-text" id="mins">0</p>
<span>Minut</span>
</div>
<div class="countdown-el seconds-c">
<p class="big-text" id="seconds">0</p>
<span>Sekund</span>
</div>
</div>