How to select and manipulate the dynamically created html element with javascript? - javascript

I am pretty new to js, and I am building a color scheme generator as a solo project.
I am now stuck on select the html element that created from dynamically.
I tried to select both label and input element below, using document.getElementByClassName but it gives me 'undefined'
I wanna select both label and input elements and add an click eventListner so that they can copy the result color code from that elements.
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>`
const colorPickerModes = [ 'monochrome', 'monochrome-dark', 'monochrome-light', 'analogic', 'complement', 'analogic-complement', 'triad quad']
const colorPickerForm = document.getElementById("colorPick-form");
const colorPickerInput = document.getElementById("colorPicker");
const colorPickerModeDropDown = document.getElementById("colorPick-mode");
const resultColorDiv = document.getElementById("result-color-div");
const resultColorCodeDiv = document.getElementById("result-code-div");
let colorPicked = "";
let modePicked = "";
let resultColorDivHtml =''
let resultCodeDivHtml=''
let colorSchemeSetStrings = [];
let resultColorSchemeSet = [];
fetchToRender()
renderDropDownList();
//listen when user change the color input and save that data in global variable
colorPickerInput.addEventListener(
"change",
(event) => {
//to remove # from the color hex code data we got from the user
colorPicked = event.target.value.slice(1, 7);
},
false
);
//listen when user change the scheme mode dropdownlist value and save that data in global variable
colorPickerModeDropDown.addEventListener('change', (event)=>{
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
})
//whe user click submit btn get data from user's input
colorPickerForm.addEventListener("submit", (event) => {
event.preventDefault();
// To get options in dropdown list
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
fetchToRender()
});
//when first load, and when user request a new set of color scheme
function fetchToRender(){
if (!colorPicked) {
//initialize the color and mode value if user is not selected anything
colorPicked = colorPickerInput.value.slice(1, 7);
modePicked = colorPickerModes[0]
}
fetch(
`https://www.thecolorapi.com/scheme?hex=${colorPicked}&mode=${modePicked}`
)
.then((res) => res.json())
.then((data) => {
let colorSchemeSetArray = data.colors;
for (let i = 0; i < 5; i++) {
colorSchemeSetStrings.push(colorSchemeSetArray[i]);
}
// to store each object's hex value
for (let i = 0; i < colorSchemeSetStrings.length; i++) {
resultColorSchemeSet.push(colorSchemeSetStrings[i].hex.value);
}
renderColor();
colorSchemeSetStrings = []
resultColorSchemeSet = [];
});
}
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color"
style="background-color: ${resultColorItem};"></div>`;
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>
Click to copy!</label>
<input class='result-code' id='${resultColor}'
type="text" value='${resultColor}'/>`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
}
function renderDropDownList() {
const colorPickerModeOptionsHtml = colorPickerModes
.map((colorPickerMode) => {
return `<option class='colorSchemeOptions' value="#">${colorPickerMode}</option>`;
})
.join("");
colorPickerModeDropDown.innerHTML = colorPickerModeOptionsHtml;
}
* {
box-sizing: border-box;
}
body {
font-size: 1.1rem;
font-family: "Ubuntu", sans-serif;
text-align: center;
margin: 0;
}
/*------Layout------*/
#container {
margin: 0 auto;
width: 80%;
}
#form-div {
width: 100%;
height:10vh;
margin: 0 auto;
}
#colorPick-form {
display: flex;
width: 100%;
height:6vh;
justify-content: space-between;
}
#colorPick-form > * {
margin: 1rem;
height: inherit;
border: 1px lightgray solid;
font-family: "Ubuntu", sans-serif;
}
#colorPick-form > #colorPicker {
width: 14%;
height: inherit;
}
#colorPick-form > #colorPick-mode {
width: 45%;
padding-left: 0.5rem;
}
#colorPick-form > #btn-getNewScheme {
width: 26%;
}
#main {
display: flex;
flex-direction:column;
width:100%;
margin: .8em auto 0;
height: 75vh;
border:lightgray 1px solid;
}
#result-color-div {
width:100%;
height:90%;
display:flex;
}
#result-color-div > *{
width:calc(100%/5);
}
#result-code-div {
width:100%;
height:10%;
display:flex;
}
.copy-label{
width:10%;
display:flex;
padding:0.5em;
font-size:0.8rem;
align-items: center;
cursor: pointer;
background-color: #4CAF50;
color: white;
}
#result-code-div .result-code{
width:calc(90%/5);
text-align: center;
border:none;
cursor: pointer;
}
.result-code:hover, .result-code:focus, .copy-label:hover, .copy-label:focus{
font-weight:700;
}
/*------Button------*/
#btn-getNewScheme {
background-image: linear-gradient(
to right,
#614385 0%,
#516395 51%,
#614385 100%
);
}
#btn-getNewScheme {
padding:0.8rem 1.5rem;
transition: 0.5s;
font-weight: 700;
background-size: 200% auto;
color: white;
box-shadow: 0 0 20px #eee;
border-radius: 5px;
display: block;
cursor: pointer;
}
#btn-getNewScheme:hover,
#btn-getNewScheme:focus {
background-position: right center; /* change the direction of the change here */
color: #fff;
text-decoration: none;
}
}
<!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=Ubuntu:wght#300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="index.css">
<title>Color Scheme Generator</title>
</head>
<body>
<div id="container">
<div>
<header><h1 class="site-title">🦎 Color Scheme Generator 🦎</h1></header>
</div>
<div id="form-div">
<form id="colorPick-form" method="get" >
<input id="colorPicker" type="color" />
<select name="colorPick-mode" id="colorPick-mode">
</select>
<button type='submit' id="btn-getNewScheme">Get Color Scheme</button>
</form>
</div>
<div id="main">
<div id="result-color-div">
</div>
<div id="result-code-div">
</div>
</div>
<script src="index.js" type="module"></script>
</body>
</html>

I think the problem is rendering timing. So you need to add event listener below the code where set innerHTML.
function renderColor() {
// to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet
.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem};"></div>`;
})
.join("");
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>
`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
// here! add event listener
const labels = document.getElementsByClassName("result-code");
Object.entries(labels).forEach(([key, label]) => {
label.addEventListener("click", (event) =>
alert(`copy color: ${event.target.value}`)
);
});
}

const resultColorCodeDiv=document.getElementById("resultColorCodeDiv")
const resultColorDiv=document.getElementById("resultColorDiv")
resultColorSchemeSet=[
{color:"red", code: "#ff0000"},
{color:"green", code: "#00ff00"},
{color:"blue", code: "#0000ff"}]
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem.color};"></div>`
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor.code}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor.code}' type="text" value='${resultColor.code}'/>`
})
.join("")
resultColorDiv.innerHTML = resultColorDivHtml
resultColorCodeDiv.innerHTML = resultCodeDivHtml
addListener(document.querySelectorAll(".result-color"))
addListener(document.querySelectorAll(".result-code"))
}
renderColor()
function addListener(elements){
for(const element of elements){
element.addEventListener("click" , ()=>{
// add copy logic here
console.log("hello")
})
}
}
<body>
<div id="resultColorDiv"></div>
<div id="resultColorCodeDiv"></div>
</body>

Related

String many operations on calculator

I am stucked with the logic of one exercise from The Odin Project. I am actually working on a simple calculator and it's almost done (except for minor bugs I think) but I need to implement the last functionality and honestly I don't know where to start.
Basically the exercise says:
"Users should be able to string together several operations and get
the right answer, with each pair of numbers being evaluated at a time.
For example, 12 + 7 - 5 * 3 = should yield 42.
Your calculator should not evaluate more than a single pair of numbers
at a time. Example: you press a number button (12), followed by an
operator button (+), a second number button (7), and finally a second
operator button (-). Your calculator should then do the following:
first, evaluate the first pair of numbers (12 + 7), second, display
the result of that calculation (19), and finally, use that result (19)
as the first number in your new calculation, along with the next
operator (-)."
The thing is, I'm very lost and confused about this last step and when I try to operate like that on my calculator it simply does not work. It's like I have to priorize multiplying and dividing over adding and subtracting, right? Could anyone enlight me?
Here is the code:
const displayPrevResult = document.querySelector('.prev-result');
const displayCurrentResult = document.querySelector('.current-result');
const equal = document.querySelector('.equal');
const decimal = document.querySelector('.decimal');
const clear = document.querySelector('.clear');
const numberBtn = document.querySelectorAll('.number');
const operatorBtn = document.querySelectorAll('.operator');
let current = '';
let previous = '';
let opString = '';
numberBtn.forEach((button) => {
button.addEventListener('click', (e) => {
getNum(e.target.textContent);
})
})
operatorBtn.forEach((button) => {
button.addEventListener('click', (e) => {
getOp(e.target.textContent);
})
})
clear.addEventListener('click', clearCalc);
// Operate when clicking equal
equal.addEventListener('click', () => {
current = parseFloat(current);
previous = parseFloat(previous);
if (opString === '+') {
current = add(previous, current);
} else if (opString === '-') {
current = subtract(previous, current);
} else if (opString === 'x') {
current = multiply(previous, current);
} else if (opString === '÷') {
if (current === 0) {
clearCalc();
displayCurrentResult.textContent = 'ERROR';
return;
}
current = divide(previous, current);
}
displayCurrentResult.textContent = current;
})
function clearCalc() {
current = '';
previous = '';
displayCurrentResult.textContent = '0';
displayPrevResult.textContent = '';
}
// Store current number, get operator and display it
function getOp(opStr) {
opString = opStr;
previous = current;
displayPrevResult.textContent = previous;
current = '';
}
// Get the number and display it
function getNum(num) {
current += num;
displayCurrentResult.textContent = current;
}
// Operating functions
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
return a / b;
}
function operate(a, b) {
return divide(b, a);
}
console.log(operate(22, 4));
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.calcContainer {
background: linear-gradient(276deg, #40a179, #77cea9);
padding: 1em;
border-radius: 5px;
border: 1px solid #000;
}
button {
padding: 1em;
margin: 0.1em;
width: 40px;
background: #a2ffaf;
border: 1px solid #fff;
border-radius: 3px;
cursor: pointer;
}
button:hover {
background: #72e782;
}
.clr {
background: #87e4bd;
}
.clr:hover {
background: #53ad88;
}
.clear {
margin: 0em 0.1em 0.5em 0.5em;
padding: 0;
}
.output-clear-container {
display: flex;
}
.output {
flex-grow: 1;
height: 40px;
background: #c2fcca;
border-radius: 5px;
border: 1px solid #fff;
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: flex-end;
padding-right: 0.5em;
margin-bottom: 0.5em;
}
.par {
margin-bottom: 0.3em;
}
.prev-result {
font-size: 14px;
padding-bottom: 0.3em;
color:#40a179;
}
.current-result {
font-size: 18px;
}
<!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="stylesheet" href="styles.css">
<script src="main.js" defer></script>
<title>Calculator</title>
</head>
<body>
<div class="calcContainer">
<div class="output-clear-container">
<div class="output">
<div class="prev-result"></div>
<div class="current-result">0</div>
</div>
<button class="clear">AC</button>
</div>
<div class="par">
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="operator clr">÷</button>
</div>
<div class="par">
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="operator clr">x</button>
</div>
<div class="par">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="operator clr">-</button>
</div>
<div class="par">
<button class="decimal clr">.</button>
<button class="number">0</button>
<button class="equal clr">=</button>
<button class="operator clr">+</button>
</div>
</div>
</body>
</html>
Thank you very much.

how do i make my X button delete the specific object inside array?

first time that I'm posting here I'm very new to web development and programming in general.
I'm currently trying to make my X button to delete the specific object inside an array.
it goes like this- the user can make 3 yellow notes-the user the values and then it stored as an object and the function displayTasks() refreshes the the notes-inside displayTasks()-when the user press X it triggers the onclick() that needs to remove this certain object but instead it always removes the last note and object in the array
how do I make it choose the exact object that inside a div?
I hope I'm clear on this!
thanks is advance!
those are the notes
class Task{
constructor(mytask,mydate,mytime){
this.task=mytask;
this.date=mydate;
this.time=mytime;
}
}
const myTask = document.getElementById("task")
const date = document.getElementById("date")
const time = document.getElementById("time")
const save = document.getElementById("save")
const reset = document.getElementById("reset")
const paragraph = document.getElementById("mypara")
const taskRow = document.getElementById("taskRow")
const tasks = []
function addTask() {
// 1. add new note to tasks array
// 2. call displayNotes()
if (tasks.length > 2) {
return alert("Too Many Notes please Complete One");
}
tasks.push(new Task(myTask.value, date.value, time.value));
resetTask();
displayTasks();
}
function resetTask() {
myTask.value = '';
date.value = '';
time.value = '';
}
function deleteTask(index) {
tasks.splice(index, 1);
displayTasks();
}
function displayTasks() {
// 1. delete all inner html in tasks row
// 2. for each element in tasks array: add a task html to the tasks row
taskRow.innerHTML = "";
for (task in tasks) {
console.log(tasks)
let taskDiv = document.createElement("div");
taskDiv.setAttribute("class", "col-sm task");
let description = document.createElement("p");
description.setAttribute("class", "description");
description.innerHTML = `${tasks[task].task}<br>`
let finishDate = document.createElement("div");
finishDate.setAttribute("class", "date");
finishDate.innerHTML = `${tasks[task].date}`;
let escape = document.createElement("p");
escape.setAttribute("class", "escape glyphicon glyphicon-remove");
escape.innerHTML = `X`;
escape.onclick = function callback() {
deleteTask(task);
console.log(task);
// escape.onclick = function() {
// deleteTask(task);
// }
}
taskDiv.appendChild(escape)
taskDiv.appendChild(description);
taskDiv.appendChild(finishDate);
taskRow.appendChild(taskDiv);
}
}
body {
background-image: url("/jpglibrary/tile.gif");
position: absolute;
left: 450px;
}
.notes{
position: absolute;
}
/* .task_input{
overflow-y: auto;
} */
.notesInput{
position: relative;
padding: 10px;
margin: 10px;
background-image: url("jpglibrary/formbg.jpg");
}
.savebutton{
position: absolute;
left: 500px;
bottom: 30px;
}
.resetbutton{
position: absolute;
left: 500px;
bottom: 0px;
}
h1{
font-family: 'cuteFont';
text-align: center;
margin-top: 30px;
font-size: 8ch;
}
.innertext{
height: 188px;
width: 170px;
position: absolute;
top: 408px;
}
.date{
position: absolute;
padding: 4px;
bottom: 7px;
height: 28px;
width: 100px;
font-size: 13px;
}
.task{
background-image: url("/jpglibrary/notebg.png");
background-repeat: no-repeat;
height: 240px;
width: 100px;
padding: 0px;
animation: fadeIn ease 2s;
}
.description{
position:absolute;
top: 40px;
padding: 3px;
width: 175px;
height: 170px ;
overflow-y: auto;
}
.escape{
padding-left: 160px;
padding-top: 20px;
}
#font-face{
font-family: cuteFont;
src: url("fonts/CuteNotes.ttf");
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<!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="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body id="main_body">
<div class='container'>
<h1>My Task Board</h1>
<!-- <div class="notes">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
</div> -->
<div class=notesInput>
<input type="text" placeholder="My task" id="task" class="task_input">
<br>
<div>
<label>Finish Date <br>
<input type="date" id="date">
</label>
</div>
<div>
<label>Finish Time<br>
<input type="time" id="time">
</div></label>
<div class="savebutton">
<input type="button" value="Save" onclick=addTask() id="save">
</div>
<div class="resetbutton">
<input type="button" onclick="resetTask()" value="Reset" id="reset">
</div>
</div>
<div id="tasksContainer" class="container">
<div id="taskRow" class="row">
</div>
</div>
</div>
</body>
<script src="Task.js"></script>
<script src="script.js"></script>
</html>
You just need to get the index of the clicked task an give that index to deleteTask().
escape.addEventListener('click', function callback(e) {
var child = e.target.parentElement;
var container = child.parentElement;
var index = Array.prototype.slice.call(container.children).indexOf(child)
deleteTask(index);
});
Working example:
class Task{
constructor(mytask,mydate,mytime){
this.task=mytask;
this.date=mydate;
this.time=mytime;
}
}
const myTask = document.getElementById("task")
const date = document.getElementById("date")
const time = document.getElementById("time")
const taskRow = document.getElementById("taskRow")
const tasks = []
function addTask() {
if (tasks.length > 2) {
return alert("Too Many Notes please Complete One");
}
tasks.push(new Task(myTask.value, date.value, time.value));
resetTask();
displayTasks();
}
function resetTask() {
myTask.value = "";
date.value = "";
time.value = "";
}
function deleteTask(index) {
tasks.splice(index, 1);
displayTasks();
}
function displayTasks() {
taskRow.innerHTML = '';
for (task in tasks) {
let taskDiv = document.createElement("div");
taskDiv.setAttribute("class", "col-sm task");
let description = document.createElement("p");
description.setAttribute("class", "description");
description.innerText = `${tasks[task].task}`;
let finishDate = document.createElement("div");
finishDate.setAttribute("class", "date");
finishDate.innerText = `${tasks[task].date}`;
let escape = document.createElement("p");
escape.setAttribute("class", "escape glyphicon glyphicon-remove");
escape.innerText = 'X';
escape.addEventListener('click', function callback(e) {
var child = e.target.parentElement;
var container = child.parentElement;
var index = Array.prototype.slice.call(container.children).indexOf(child)
deleteTask(index);
});
taskDiv.appendChild(escape)
taskDiv.appendChild(description);
taskDiv.appendChild(finishDate);
taskRow.appendChild(taskDiv);
}
}
.container {
width: 250px;
text-align: center;
}
.inputs, #taskRow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.task {
border: 1px solid black;
text-align: left;
}
.escape {
cursor: pointer;
text-align: right;
margin: 0;
}
<div class='container'>
<h1>My Task Board</h1>
<div class=notesInput>
<div class="inputs">
<label for="task">Task</label>
<input type="text" placeholder="My task" id="task" class="task_input">
</div>
<div class="inputs">
<label for="date">Finish Date</label>
<input type="date" id="date">
</div>
<div class="inputs">
<label for="date">Finish Time</label>
<input type="time" id="time">
</div>
<div class="inputs">
<input type="button" onclick="resetTask()" value="Reset" id="reset">
<input type="button" value="Save" onclick=addTask() id="save">
</div>
</div>
<div id="tasksContainer" class="container">
<div id="taskRow" class="row"></div>
</div>
</div>

How to remove an object from an array in local storage

I am trying to remove a note from local storage by identifying its
title. I checked w3schools and this forum for info. I am able to save
the array but, I can't remove a specific note.
I tried, no change, an example of what I am trying to achieve,
This is my local storage before removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}, {title: "Read", content: "Go to the library"}] 0: {title:
"Laundry", content: "Fold Clothes"} 1: {title: "Cook", content: "Buy
Food"} 2: {title: "Read", content: "Go to the library"}
My desired output after removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}] 0: {title: "Laundry", content: "Fold Clothes"} 1: {title:
"Cook", content: "Buy Food"}
I want to be able to remove an item based on its title Read
const editNote = (e) => {
saveContent.addEventListener('click', (e) => {
e.preventDefault()
let notes = []
let note = {
title: noteTitle.value,
content: noteContent.value
}
// Parse the serialized data back into an aray of objects
notes = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
notes.push(note);
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(notes));
// input.textContent = note.title
//remove notes by id
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
}
}
delNote.addEventListener('click', (e) => {
removeNote()
e.preventDefault()
// window.location.href='index.html'
})
})
}
editNote()
You need to set item into local storage after you update your data
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
localStorage.setItem('items', JSON.stringify(notes))
}
}
localStorage.removeItem('ITEM TO REMOVE');
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
I eventually figured it out. Thank you all for replying and providing guidelines.
let input = document.querySelector('.input-bar')
let addItem = document.querySelector('.submit-btn')
let clearAll = document.querySelector('.clear-btn')
// pay attension to indentation and ele location it will determine success
addItem.addEventListener('click', (e) => {
e.preventDefault()
// Parse the serialized data back into an aray of objects
items = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
items.push(input.value);
item = input.value
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(items));
var clear = document.createElement('button')
clear.innerHTML= '<i class="fa fa-trash" style="font-size:20px ;color: #ac2412"></i>'
let itemsEl = document.getElementById('items')
let para = document.createElement("P");
var t = document.createTextNode(`${input.value}`);
para.appendChild(t);
para.appendChild(clear)
itemsEl.appendChild(para);
input.value = ''
clear.addEventListener('click', (e) => {
itemsEl.removeChild(para)
e.preventDefault()
for (let index = 0; index < items.length; index++) {
if (items[index] === para.textContent) {
items.splice(index, 1)
localStorage.setItem('items', JSON.stringify(items));
}
}
})
})
clearAll.addEventListener('click', (e) => {
document.getElementById('items').innerHTML = ''
localStorage.clear()
})
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
color: white;
background-color: black;
margin: 40px 0px;
text-align: center;
}
input {
width: 300px;
height: 46px;
outline: none;
background: transparent;
border-color: silver;
border-radius: 0;
color: var(--mainWhite);
font-size: 1.7rem;
}
h1 {
margin: 20px 0px;
}
.submit-btn {
margin: 0px 5px;
width: 50px;
height: 50px;
outline: none;
/* color: white; */
background-color: rgb(21, 96, 194);
color: white;
font-size: 1.7rem;
}
.items-list {
list-style-type: none;
}
li {
display: inline-flex;
border: 1px solid slategrey;
font-size: 22px;
margin: 20px 0px 0px 0px;
}
button {
outline: none;
margin: 0px 0px 0px 200px;
}
.clear-btn {
width: 100px;
height: 40px;
margin: 30px;
outline: none;
background-color: rgb(21, 96, 194);
color: white;
font-size: 20px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<title>Groceries</title>
</head>
<body>
<h1>Grocery List</h1>
<div>
<input class="input-bar" type="text">
<span>
<button class="submit-btn">
<i class="fa fa-pencil" aria-hidden="true"></i>
</button>
</span>
<ul class="items-list" id="items"></ul>
</div>
<button class="clear-btn">Clear</button>
<script src="index.js"></script>
</body>
</html>

eventListener is not running after the page is updated

I have written this code to get the squares of a grid to change their background color to black upon a mouseover event. It works when the page initially loads, but if I create a new grid the mouseover event no longer works.
I updated the original post with a snippet. Sorry I didn't do that from the beginning.
let number = 16;
makeGrid(number);
function makeGrid(number) {
for (let i=0; i < number; i++) {
for (let j=0; j < number; j++) {
const rows = document.createElement('div');
const container = document.getElementById('container')
rows.setAttribute('class', 'rows');
container.appendChild(rows);
}
}
container.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
container.style.gridTemplateRows = `repeat(${number}, 1fr)`;
}
//create new grid with on button
let newGrid = document.getElementById('newGrid');
newGrid.addEventListener('click', () => {
let number = prompt('Enter a number');
let container = document.getElementById('container');
container.textContent = '';
makeGrid(number);
})
//change background color to black
let changeClass = document.querySelectorAll('.rows');
changeClass.forEach((item) => {
item.addEventListener('mouseover', e => {
item.style.backgroundColor = 'black';
})
})
body {
background-color: rgb(5, 51, 5) ;
}
#container {
margin: auto;
width: 500px;
height: 500px;
display: grid;
border-style: solid;
border-width: thin;
border-color: lightslategray;
background-color: white;
}
.rows{
}
.black { background-color: black;
}
#header {
text-align: center;
}
#button {
text-align: center;
}
#footer {
text-align: center;
}
#newGrid {
background-color: lightgray;
color: darkcyan;
font-size: 20px;
padding: 12px 28px;
border-radius: 0px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id='header'>Etch-a-Sketch</h1>
<br>
<div id='button'>
<button id='newGrid' class='button'>New Grid</button>
</div>
<br>
<br>
<div id='container'></div>
<br>
<footer id='footer'>Made by: Joe Maniaci</footer>
<script src="main.js"></script>
</body>
</html>
When you query the DOM with document.querySelectorAll('.rows') and add the event listeners, there is only one "grid" in the DOM at that time. When a "grid" is subsequently added to the DOM, as triggered by the user's click event, you must instantiate event listeners on the newly added DOM nodes too.
A way to avoid this problem and a better approach overall in your situation is to use delegated event listeners. For example:
document.addEventListener('mouseover', e=>{
if(e.target.matches(‘.myClickableItemClass’){
e.target.style.backgroundColor = 'black';
}
}
Learn more about event delegation here: https://medium.com/#bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983

localStorage is not working in JavaScript

I'm trying to make a Single Page Application with pure JavaScript (no additional frameworks or libraries). The problem is that the values I add to the TODO list are not storing in the localStorage (and are not showing).
I would appreciate any help with that task.
How can I simplify the code? (without using any additional libraries and frameworks (ex.jquery etc.))
Here is my code:
let inputTask = document.getElementById('toDoEl');
let editTask = document.getElementById('editTask');
let checkTask = document.getElementById('list');
let emptyList = document.getElementById('emptyList');
let items = [];
let id = [];
let labelToEdit = null;
const empty = 0;
let pages = ['index', 'add', 'modify'];
load();
function load() {
items = loadFromLocalStorage();
id = getNextId();
items.forEach(item => renderItem(item));
}
function show(shown) {
location.href = '#' + shown;
pages.forEach(function(page) {
document.getElementById(page).style.display = 'none';
});
document.getElementById(shown).style.display = 'block';
return false;
}
function getNextId() {
for (let i = 0; i<items.length; i++) {
let item = items[i];
if (item.id > id) {
id = item.id;
}
}
id++;
return id;
}
function loadFromLocalStorage() {
let localStorageItems = localStorage.getItem('items');
if (localStorageItems === null) {
return [];
}
return JSON.parse(localStorageItems);
}
function saveToLocalStorage() {
localStorage.setItem('items', JSON.stringify(items));
}
function setChecked(checkbox, isDone) {
if (isDone) {
checkbox.classList.add('checked');
checkbox.src = 'https://image.ibb.co/b1WeN9/done_s.png';
let newPosition = checkTask.childElementCount - 1;
let listItem = checkbox.parentNode;
listItem.classList.add('checked');
checkTask.removeChild(listItem);
checkTask.appendChild(listItem);
} else {
checkbox.classList.remove('checked');
checkbox.src = 'https://image.ibb.co/nqRqUp/todo_s.png';
let listItem = checkbox.parentNode;
listItem.classList.remove('checked');
}
}
function renderItem(item) {
let listItem = document.getElementById('item_template').cloneNode(true);
listItem.style.display = 'block';
listItem.setAttribute('data-id', item.id);
let label = listItem.querySelector('label');
label.innerText = item.description;
let checkbox = listItem.querySelector('input');
checkTask.appendChild(listItem);
setChecked(checkbox, item.isDone);
emptyList.style.display = 'none';
return listItem;
}
function createNewElement(task, isDone) {
let item = { isDone, id: id++, description: task };
items.push(item);
saveToLocalStorage();
renderItem(item);
}
function addTask() {
if (inputTask.value) {
createNewElement(inputTask.value, false);
inputTask.value = '';
show('index');
}
}
function modifyTask() {
if (editTask.value) {
let item = findItem(labelToEdit);
item.description = editTask.value;
labelToEdit.innerText = editTask.value;
saveToLocalStorage();
show('index');
}
}
function findItem(child) {
let listItem = child.parentNode;
let id = listItem.getAttribute('data-id');
id = parseInt(id);
let item = items.find(item => item.id === id);
return item;
}
// Chanhe img to checked
function modifyItem(label) {
labelToEdit = label;
editTask.value = label.innerText;
show('modify');
editTask.focus();
editTask.select();
}
function checkItem(checkbox) {
let item = findItem(checkbox);
if (item === null) {
return;
}
item.isDone = !item.isDone;
saveToLocalStorage();
setChecked(checkbox, item.isDone);
}
function deleteItem(input) {
let listItem = input.parentNode;
let id = listItem.getAttribute('data-id');
id= parseInt(id);
for (let i in items) {
if (items[i].id === id) {
items.splice(i, 1);
break;
}
}
if (items.length === empty) {
emptyList.style.display = 'block';
}
saveToLocalStorage();
listItem.parentNode.removeChild(listItem);
}
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
h2, li, #notification {
text-align: center;
}
h2 {
font-weight: normal;
margin: 0 auto;
padding-top: 20px;
padding-bottom: 20px;
}
#root {
width: 400px;
height: 550px;
margin: 0 auto;
position: relative;
}
#root>ul {
display: block;
}
#addButton {
display: block;
margin: 0 auto;
}
.checkbox, .delete {
height: 24px;
bottom: 0;
}
.checkbox {
float: left;
}
.delete {
float: right;
}
ul {
margin: 20px 30px 0 30px;
padding-top: 20px;
padding-left: 20px;
text-align: center;
}
#toDoEl {
width: 50%;
}
li {
width: 100%;
list-style: none;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px auto;
}
label {
margin: 0 auto;
text-align: justify;
text-justify: inter-word;
}
label:hover {
cursor: auto;
}
li.checked {
background-color: gray;
}
span.button {
cursor: pointer;
}
#add, #modify {
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Homework 12 - Simple TODO List</title>
<link rel="stylesheet" href="./assets/styles.css">
</head>
<body>
<div id="root">
<!--Main page-->
<div id="index">
<h2>Simple TODO Application</h2>
<button class="button" id="addButton" onclick="show('add')">Add New Task</button>
<p id="emptyList">TODO is empty</p>
<ul id="list">
<li id="item_template" style="display: none">
<input class="checkbox" type="image" alt="checkbox" src="https://image.ibb.co/nqRqUp/todo_s.png" onclick="checkItem(this)">
<label onclick="modifyItem(this)"></label>
<input id="delete" class="delete" type="image" alt="remove" src="https://image.ibb.co/dpmqUp/remove_s.jpg" onclick="deleteItem(this)">
</li>
</ul>
</div>
<!--Add page-->
<div id="add">
<h2>Add Task</h2>
<input type="text" id="toDoEl">
<button class="button cancel" onclick="show('index')">Cancel</button>
<button class="button save" onclick="addTask()">Save changes</button>
</div>
<!--Modify page-->
<div id="modify">
<h2>Modify item</h2>
<input type="text" id="editTask">
<button class="button cancel" onclick="show('index')">Cancel</button>
<button class="button save" onclick="modifyTask()">Save changes</button>
</div>
</div>
<script src="./src/app.js"></script>
</body>
</html>
Your code does appear to work. If you console.log(JSON.parse(localStorageItems)) right above line 49 in the loadFromLocalStorage function, it shows as expected in the console. Also, upon refreshing the items persist.
If what you mean is that you're checking localStorage and you don't see the items, it might be that you're looking at the preview version of localStorage. (I'm assuming you're using Chrome.) Hover over the top of the empty section and pull down, this should reveal the values stored. If you click on one, it should show in the preview section. I think this was a Chrome dev tools UI change recently implemented.
I checked your code in Codepen and it works.

Categories