How to add button for each item in localstorage to remove that item?
I have code for setItem and getItem from localstorage, but I don't know how I can add a button or x for each item to remove it.
2020-03-01 March x
2020-04-01 April x
It looks like add item to card or remove item from card.
plz help me
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function () {
$("#inpkey").datepicker();
});
</script>
<style>
fieldset{
margin-bottom:20px;
}
input{
padding: 7px;
height:40px;
}
</style>
</head>
<body>
<fieldset>
<input type="text" id="inpkey" placeholder="Click and select date">
<input type="text" id="inpvalue">
<button type="button" id="btninsert">Save</button>
</fieldset>
<fieldset>
<div id="output"></div>
</fieldset>
<script>
const inpkey = document.getElementById("inpkey");
const inpavv = document.getElementById("inpvalue");
const spara = document.getElementById("btninsert");
const output = document.getElementById("output");
spara.onclick = function () {
const key = inpkey.value;
const value = inpavv.value;
console.log(key);
console.log(value);
if (key && value ) {
localStorage.setItem(key, value );
location.reload();
}
};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
console.log(localStorage.getItem(key));
output.innerHTML += `${key}:     ${value} <p />`;
}
</script>
</body>
</html>
Something like this: Note JSFiddle had trouble removing the last element. Might be something I overlooked in the code. Good luck.
const setup = () => {
const spara = document.querySelector('#btninsert');
const output = document.querySelector('#output');
spara.addEventListener('click', addMyEntry);
output.addEventListener('click', removeMyEntry);
insertEntries(output);
};
const insertEntries = (target) => target.insertAdjacentHTML('beforeend', loadEntryHTML());
const loadEntryHTML = () => {
let html = '';
if(localStorage.length !== 0) {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
html += createEntryHTML(key, value);
}
}
return html;
};
const createEntryHTML = (key, value) => `<p><label class="lbl_key">${key}:</label><span class="sp_value">${value}</span> remove<p/>`;
const addMyEntry = () => {
const inpkey = document.querySelector('#inpkey');
const inpavv = document.querySelector('#inpvalue');
const key = inpkey.value;
const value = inpavv.value;
if (key && value ) {
localStorage.setItem(key, value );
const output = document.querySelector('#output');
output.insertAdjacentHTML('beforeend', createEntryHTML(key, value));
}
};
const removeMyEntry = (event) => {
const target = event.target;
if(target.nodeName === 'A') {
event.currentTarget.removeChild(target.parentNode);
localStorage.removeItem(target.dataset.key);
}
};
//load
window.addEventListener('load', setup);
.lbl_key {
padding-right: 1em;
}
<fieldset>
<input type="text" id="inpkey" placeholder="Click and select date">
<input type="text" id="inpvalue">
<button type="button" id="btninsert">Save</button>
</fieldset>
<fieldset>
<div id="output"></div>
</fieldset>
A better solution to build elements dynamically.
const app = document.getElementById("app");
const localStorage = [1, 2, 3, 4];
for (let index = 0; index < localStorage.length; index++) {
// const key = localStorage.key(index);
// const value = localStorage.getItem(key);
let div = document.createElement("div");
div.className = "cart_item";
div.id = "cart_item_" + index;
div.textContent = localStorage[index] + new Date().toUTCString() + "";
let cross = document.createElement("span");
cross.className = "cross";
cross.textContent = " X";
cross.addEventListener("click", function remove() {
alert("Remove item");
});
div.appendChild(cross);
app.appendChild(div);
}
<!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>Static Template</title>
<link rel="stylesheet" href="app.css" />
<!-- <script src="https://deepak-proxy-server.herokuapp.com/https://gist.githubusercontent.com/deepakshrma/4b6a0a31b4582d6418ec4f76b7439781/raw/e7377474ce9e411b4d8de4b10f4437a24774c0e2/Mapper.js"></script> -->
<style>
.cart_item{
border: 1px solid;
padding: 20px 40px;
}
.cross {
color: red;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
</div>
</body>
</html>
Related
Basically, I have a function that creates N input fields based on user choice, then I want to get those inputs for processing later on, though for some reason it creates a copy of the return over and over again, unless I add something like "conj.pop()" in the return. I wouldn't like to work not knowing why it only works if I pop the last one.
I put a console.log to keep track and the returned array was something like this:
Array(3)
0: 'A'
1: 'B'
2: (3) ['A','B','Array(3)]
If you expand this last array it repeats infinitely this very same description.
OBS: The inputs I've been using were simple 2,2 and A B, C D.
OBS2: The code wasn't previously in english so I translated some stuff, and left other small ones as they were variables only.
document.getElementById("ok1").onclick = () => {
const esp_qtd = document.getElementById("esp_qtd").value;
const car_qtd = document.getElementById("car_qtd").value;
document.getElementById("parte1").classList.add("invisivel");
document.getElementById("parte2").classList.remove("invisivel");
console.log(esp_qtd, car_qtd);
const generateFields = (tipo) => {
const qtd = document.getElementById(tipo + "_qtd").value;
const parent = document.getElementById(tipo + "_lista");
for (let i = 0; i < qtd; i++) {
const input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("id", (tipo + i));
parent.appendChild(input);
if (qtd > 5) {
if (((i + 1) % 3) == 0) parent.appendChild(document.createElement("br"));
}
console.log(i);
}
}
generateFields("esp");
generateFields("car");
const inputFields = (tipo, conj) => {
const qtd = document.getElementById(tipo + "_qtd").value;
for (let i = 0; i < qtd; i++) {
conj[i] = document.getElementById(tipo + i).value;
console.log("Iteration: " + i, conj);
}
return conj;
}
document.getElementById("ok2").onclick = () => {
const conjE = [];
const conjC = [];
conjE.push(inputFields("esp", conjE));
conjC.push(inputFields("car", conjC));
console.log(conjE);
console.log(conjC);
}
}
* {
font-family: 'Roboto', sans-serif;
font-size: 14pt;
margin-top: 1rem;
}
.invisivel {
display: none;
}
label {
margin-top: 1rem;
}
input {
margin-top: 0.5rem;
margin-right: 1rem;
margin-bottom: 0.5rem;
}
button {
margin-top: 1rem;
}
<!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>DOC</title>
<link rel="stylesheet" href="style.css">
<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=Roboto&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<!-- PART 1 -->
<div id="parte1">
<form>
<label>N1</label><br>
<input type="text" id="esp_qtd"><br>
<label>N2</label><br>
<input type="text" id="car_qtd"><br>
<button id="ok1" type="button">OK</button>
</form>
</div>
<!-- PART 2 -->
<div id="parte2" class="invisivel">
<div id="esp_lista">
<label>ELEMENTS 1</label><br>
</div>
<div id="car_lista">
<label>ELEMENTS 2</label><br>
</div>
<button id="ok2" type="button">OK</button>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
Please change your JS as follows:
document.getElementById("ok1").onclick = () => {
const esp_qtd = document.getElementById("esp_qtd").value;
const car_qtd = document.getElementById("car_qtd").value;
document.getElementById("parte1").classList.add("invisivel");
document.getElementById("parte2").classList.remove("invisivel");
console.log(esp_qtd, car_qtd);
const generateFields = (tipo) => {
const qtd = document.getElementById(tipo + "_qtd").value;
const parent = document.getElementById(tipo + "_lista");
for (let i = 0; i < qtd; i++) {
const input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("id", tipo + i);
parent.appendChild(input);
if (qtd > 5) {
if ((i + 1) % 3 == 0) parent.appendChild(document.createElement("br"));
}
console.log(i);
}
};
generateFields("esp");
generateFields("car");
const inputFields = (tipo, conj) => {
const qtd = document.getElementById(tipo + "_qtd").value;
console.log("Conj:" + qtd);
for (let i = 0; i < qtd; i++) {
conj[i] = document.getElementById(tipo + i).value;
console.log("Iteration: " + i, conj);
}
return conj;
};
document.getElementById("ok2").onclick = () => {
const conjE = [];
const conjC = [];
inputFields("esp", conjE);
inputFields("car", conjC);
console.log(conjE);
console.log(conjC);
};
};
I have only removed conjE.push() and conjC.push().
Explanation:
You are passing an array to store your data in it. But you're also returning the same array and storing it in it again. This creates an infinite loop of values. Either pass the variable or return the list.
I am still learning Javascript and don't understand why I get wrong values when calling getAttribute('data-value') from removeButton after swapping elements with swapping() function.
const addButton = document.querySelector('.addButton');
const swapButton = document.querySelector('.swapButton');
var input = document.querySelector('.input');
const draggable_list = document.getElementById('draggable-list');
let items;
const array = [];
const listItems = [];
let dragStartIndex;
class item {
constructor(itemName) {
this.createDiv(itemName);
}
createDiv(itemName) {
let input = document.createElement('input');
input.value = itemName;
input.disabled = true;
input.classList.add('item_input');
input.type = 'text';
let removeButton = document.createElement('button');
removeButton.innerHTML = 'REMOVE';
removeButton.classList.add('removeButton');
draggable_list.appendChild(items);
items.appendChild(removeButton);
removeButton.addEventListener('click', (event) => {
let itemNumber = event.target.closest('li').getAttribute('data-value');
console.log("The deleted number has a value of: ", itemNumber); //returns wrong 'data-value' numbers
if (event && event.target.parentElement) {
this.remove(event.target.parentElement, input.value);
}
});
}
//Remove numbers
remove(item, value) {
draggable_list.removeChild(item);
//delete from array
let indexArray = array.indexOf(value);
array.splice(indexArray,1);
//delete from listItems
listItems.splice(indexArray,1);
//redfine indexes of li elements after deletion
array.forEach((numbers,index) => {
items.setAttribute('data-index', index);
items.setAttribute('data-value', numbers);
} );
}
}
//Create numbers
async function create() {
if (input.value != '') {
array.push(input.value);
array.forEach((numbers,index) => {
//if numbers already exists in the UI, then pass?
items = document.createElement('li');
items.setAttribute('data-index', index);
items.setAttribute('data-value', numbers);
items.innerHTML = `
<div class="draggable" draggable="true">
<p class="phone-number" id="div">${numbers}</p>
<i class="fas fa-grip-lines"></i>
</div>`;
} );
listItems.push(items); //used for swapping
new item(input.value);
input.value = ''
}
}
// Swap list items
function swapItems(fromIndex, toIndex) {
const itemOne = listItems[fromIndex].querySelector('.draggable');
const itemTwo = listItems[toIndex].querySelector('.draggable');
//swap UI items
listItems[fromIndex].appendChild(itemTwo);
listItems[toIndex].appendChild(itemOne);
//swap array items
[array[fromIndex], array[toIndex]] = [array[toIndex], array[fromIndex]];
console.log("This is array after swapping: ",array);
//redefine li index and values
array.forEach((numbers,index) => {
items.setAttribute('data-index', index);
items.setAttribute('data-value', numbers);
console.log("The values of the numbers aftwer swapping are: ", numbers); //'data-value' numbers are correct here
} )
}
function swapping(){
const draggables = document.querySelectorAll('.draggable');
const dragListItems = document.querySelectorAll('.draggable-list li');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', dragStart);
});
dragListItems.forEach(item => {
item.addEventListener('dragover', dragOver);
item.addEventListener('drop', dragDrop);
});
}
function dragStart() {
dragStartIndex = +this.closest('li').getAttribute('data-index');
}
function dragOver(e) {
e.preventDefault();
}
function dragDrop() {
const dragEndIndex = +this.getAttribute('data-index');
swapItems(dragStartIndex, dragEndIndex);
}
addButton.addEventListener('click', create);
swapButton.addEventListener('click', swapping);
<!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="style.css"> -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/4690c1252a.js" crossorigin="anonymous"></script>
</head>
<body>
<h1><span class="styling">Add a number</span> </h1>
<div class="input_div">
<input type="text" class="input" placeholder="Add Task" />
<button class="addButton">+</button>
<button class="swapButton">SWAP</button>
</div>
<ul class="draggable-list" id="draggable-list"></ul>
<script src="code.js"></script>
</body>
</html>
If I try inserting the numbers 1, 2, 3 for example, I swap 1 with 2. Then delete 1, itemNumber will have a vlue of 2 instead of 1. Why is that?
const addButton = document.querySelector('.addButton');
const swapButton = document.querySelector('.swapButton');
var input = document.querySelector('.input');
const draggable_list = document.getElementById('draggable-list');
let items;
const array = [];
const listItems = [];
let dragStartIndex;
class item {
constructor(itemName) {
this.createDiv(itemName);
}
createDiv(itemName) {
let input = document.createElement('input');
input.value = itemName;
input.disabled = true;
input.classList.add('item_input');
input.type = 'text';
let removeButton = document.createElement('button');
removeButton.innerHTML = 'REMOVE';
removeButton.classList.add('removeButton');
draggable_list.appendChild(items);
items.appendChild(removeButton);
removeButton.addEventListener('click', (event) => {
let itemNumber = event.target.closest('li').dataset.value;
console.log("The deleted number has a value of: ", itemNumber);
if (event && event.target.parentElement) {
this.remove(event.target.parentElement, itemNumber);
}
});
}
//Remove numbers
remove(item, value) {
draggable_list.removeChild(item);
//delete from array
let indexArray = array.indexOf(value);
array.splice(indexArray, 1);
//delete from listItems
listItems.splice(indexArray, 1);
//redfine indexes of li elements after deletion
array.forEach((numbers, index) => {
draggable_list.children[index].dataset.index = index;
draggable_list.children[index].dataset.value = numbers;
});
}
}
//Create numbers
async function create() {
if (input.value != '') {
array.push(input.value);
array.forEach((numbers, index) => {
//if numbers already exists in the UI, then pass?
items = document.createElement('li');
items.dataset.index = index;
items.dataset.value = numbers;
items.innerHTML = `
<div class="draggable" draggable="true">
<p class="phone-number" id="div">${numbers}</p>
<i class="fas fa-grip-lines"></i>
</div>`;
});
listItems.push(items); //used for swapping
new item(input.value);
input.value = ''
}
}
// Swap list items
function swapItems(fromIndex, toIndex) {
const itemOne = listItems[fromIndex].querySelector('.draggable');
const itemTwo = listItems[toIndex].querySelector('.draggable');
//swap UI items
listItems[fromIndex].prepend(itemTwo);
listItems[toIndex].prepend(itemOne);
//swap array items
[array[fromIndex], array[toIndex]] = [array[toIndex], array[fromIndex]];
console.log("This is array after swapping: ", array);
//redefine li index and values
array.forEach((numbers, index) => {
draggable_list.children[index].dataset.index = index;
draggable_list.children[index].dataset.value = numbers;
console.log("The values of the numbers after swapping are: ", numbers);
})
}
function swapping() {
const draggables = document.querySelectorAll('.draggable');
const dragListItems = document.querySelectorAll('.draggable-list li');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', dragStart);
});
dragListItems.forEach(item => {
item.addEventListener('dragover', dragOver);
item.addEventListener('drop', dragDrop);
});
}
function dragStart() {
dragStartIndex = +this.closest('li').dataset.index;
}
function dragOver(e) {
e.preventDefault();
}
function dragDrop() {
const dragEndIndex = +this.dataset.index;
swapItems(dragStartIndex, dragEndIndex);
}
addButton.addEventListener('click', create);
swapButton.addEventListener('click', swapping);
<!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="style.css"> -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/4690c1252a.js" crossorigin="anonymous"></script>
</head>
<body>
<h1><span class="styling">Add a number</span> </h1>
<div class="input_div">
<input type="text" class="input" placeholder="Add Task" />
<button class="addButton">+</button>
<button class="swapButton">SWAP</button>
</div>
<ul class="draggable-list" id="draggable-list"></ul>
<script src="code.js"></script>
</body>
</html>
I'm learning java script and I'm currently working with testing in javiscritp, I've done this code that you can look at, but I don't know how to reverse now the order of these cubes to be 2 up and 1 down (see what I want in the picture) I know I need to change something for loops but I fail in any way to get what I want.
let Tabela = (function () {
const dajRed = function (tabela) {
let red = document.createElement("tr");
tabela.appendChild(red);
return red;
}
const dajCeliju = function (red, prikazi) {
let celija = document.createElement("td");
if (!prikazi) celija.style = "display:none;";
red.appendChild(celija)
return celija;
}
const crtaj = function (x, y) {
const body = document.getElementsByTagName("body")[0];
let tabelaEl = document.createElement("table");
body.appendChild(tabelaEl);
for (let i = 0; i < y; i++) {
let red = dajRed(tabelaEl);
for (let j = 0; j < x; j++) {
dajCeliju(red, j < i);
}
}
}
return {
crtaj: crtaj
}
}());
//table.crtaj(3,3)
//i=0 ⍉⍉⍉
//i=1 ⎕⍉⍉
//i=2 ⎕⎕⍉
//Tabela.crtaj(8, 8);
let assert = chai.assert;
describe('Tabela', function() {
describe('crtaj()', function() {
it('should draw 3 rows when parameter are 2,3', function() {
Tabela.crtaj(2,3);
let tabele = document.getElementsByTagName("table");
let tabela = tabele[tabele.length-1]
let redovi = tabela.getElementsByTagName("tr");
assert.equal(redovi.length, 3,"Broj redova treba biti 3");
});
it('should draw 2 columns in row 2 when parameter are 2,3', function() {
Tabela.crtaj(2,3);
let tabele = document.getElementsByTagName("table");
let tabela = tabele[tabele.length-1]
let redovi = tabela.getElementsByTagName("tr");
let kolone = redovi[2].getElementsByTagName("td");
let brojPrikazanih = 0;
for(let i=0;i<kolone.length;i++){
let stil = window.getComputedStyle(kolone[i])
if(stil.display!=='none') brojPrikazanih++;
}
assert.equal(brojPrikazanih, 2,"Broj kolona treba biti 2");
});
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mocha Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<style>
td{
border: 1px solid black;
height: 20px;
width: 20px;
}
</style>
</head>
<body>
<div id="ispis"></div>
<div id="mocha"></div>
<script src="https://unpkg.com/chai/chai.js"></script>
<script src="https://unpkg.com/mocha/mocha.js"></script>
<script class="mocha-init">
mocha.setup('bdd');
mocha.checkLeaks();
</script>
<script src="tabela.js"></script>
<script src="test.js"></script>
<script class="mocha-exec">
mocha.run();
</script>
</body>
</html>
Invert the check in dajCeliju:
if (prikazi) celija.style = "display:none;";
OR second option - change the params:
dajCeliju(red, j >= i);
Is this what you need?
I am having some difficulty filtering through a list of tasks in To Do List project.
I use an object to store the core properties of each task created like the id, content, completed, and date.
The filter should occurs after the user selects an option in a drop down menu.
I use an Event Listener to catch the id of the option selected, but I don't know what to do with that Id. For example, when the user selects the option 'completed' the app should only display the completed task, or the tasks that have a property of 'completed:true'.
I also want to filter the list in a fancy way such as make tasks fade out when filtering.
URL: https://alonzocarlos95.github.io/WDD-330/
//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">
<!--ClockPicker libraries-->
<link rel="stylesheet" href="https://weareoutman.github.io/clockpicker/dist/jquery-clockpicker.min.css"></link>
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Moment JS library CDN -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.25.1/moment.min.js"></script> -->
<!--Material Icons and Fonts-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<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=Poppins:ital,wght#0,200;1,100&display=swap" rel="stylesheet">
<!--Small view-->
<link rel="stylesheet" href="css/small.css" media="screen">
<title>Document</title>
</head>
<body>
<header>
<nav>
<ul>
<li><span class="material-icons">done</span></li>
<li class="drop-down" ><div class="dropdown"><button class="dropbtn" onclick="showModal()">All Lists<span class="material-icons" style="vertical-align: middle;">arrow_drop_down</span></button><div id="myDropdown" class="dropdown-content"><span id="select1">All Lists</span><span id="select2">Active</span><span id="select3">Completed</span></div></div></li>
<li><span class="label_list">BYU-Idaho To do List</span></li>
<li><span class="material-icons">search</span></li>
<li><img src="images/b2-removebg-preview.png" alt="logo"></li>
</ul>
</nav>
</header>
<main>
<div class="notes">
<img id="no_tasks" src="images/palms-300x220.png" alt="No tasks">
</div>
<div class="main_list" id="main_list">
<ul id="parentList">
</ul>
</div>
<div class="new_task_container" id="container_schedule">
<div class="new_task" id="new_todo">
<label>What is to be done?</label>
<div class="new_input">
<input type="text" name="todo" id="todo" placeholder="Enter task here">
<span class="material-icons">keyboard_voice</span>
</div>
<label>Due Date</label>
<input type="date" id="date" name="date" placeholder="Date not set">
</div>
<div class="new_task_group2">
<div class="new_time" id="new_time_container">
<input type="text" name="time" id="time" placeholder="Time not set(all day)">
<span class="material-icons">schedule</span>
<!-- <input type="checkbox" style="display: none;"> -->
</div>
</div>
</div>
</main>
<div class="add_task">
<button id="add" class="bounce">+</button>
</div>
<script src="https://weareoutman.github.io/clockpicker/dist/jquery-clockpicker.min.js"></script>
<script src="js/todo.js"></script>
</body>
</html>
//Javacript
let toDoList = [];
let options = {weekday:'long', year:'numeric', month:'long', day:'numeric'};
let indicador = 0;
let list_container = document.getElementById('main_list');
document.getElementById('container_schedule').style.display = 'none';
const chosenDate = document.getElementById("date");
const time = document.getElementById('new_time_container');
let ulTasks = document.getElementById('parentList');
time.style.display = 'none';
document.getElementById('add').addEventListener('click', () => {
document.getElementById('container_schedule').style.display = 'block';
document.getElementById('add').innerHTML = '<span class="material-icons">done</span>';
let inputNewTask = document.getElementById("todo");
let valInputNewTask = inputNewTask.value;
let valInputNewTask2 = inputNewTask.value;
let dateSet = document.getElementById('date').value;
if(indicador === 0){
indicador = 1;
list_container.style.display = "none";
}else {
if(!isBlank(valInputNewTask)){ //Valida si el valor del input no es null o undefined o whitespace
indicador = 0;
inputNewTask.value = "";
inputNewTask.focus();
let newDateSet = valDate(dateSet);
taskCreated();
manageTask(valInputNewTask2,newDateSet);
}
else {
alert("Enter task at first.");
}
}
} );
document.getElementById('date').addEventListener('change',() => {
// alert("New date");
time.style.display = 'flex';
});
function taskCreated(){
document.getElementById('container_schedule').style.display = 'none';
// debugger;
if(document.getElementsByClassName('notes').length >= 1){
document.getElementsByClassName('notes')[0].remove();
}
document.getElementById('add').textContent = '+';
}
/*Clock picker functionality*/
$("input[name=time]").clockpicker({
placement: 'bottom',
align: 'left',
autoclose: true,
default: 'now',
donetext: "Select",
init: function() {
console.log("colorpicker initiated");
},
beforeShow: function() {
console.log("before show");
},
afterShow: function() {
console.log("after show");
},
beforeHide: function() {
console.log("before hide");
},
afterHide: function() {
console.log("after hide");
},
beforeHourSelect: function() {
console.log("before hour selected");
},
afterHourSelect: function() {
console.log("after hour selected");
},
beforeDone: function() {
console.log("before done");
},
afterDone: function() {
console.log("after done");
}
});
function isBlank(str) {
//debugger;
return (!str || /^\s*$/.test(str));
}
function valDate(dateToDo){
// debugger;
if(dateToDo === null || dateToDo === ''){
dateToDo = "No date";
return dateToDo;
}
else {
dateToDo = new Date(dateToDo);
dateToDo.setDate(dateToDo.getDate()+1);
// testDate = new Date(Date.UTC(dateToDo));
dateToDo = dateToDo.toLocaleString('en-US',options);
return dateToDo;
}
}
function manageTask(getTask,dateSet){
const todo = {
id: Date.now(),
content: getTask,
completed: false,
date: dateSet
}
toDoList.push(todo);
addToLocalStorage(toDoList);
// storeData(todo);
}
function addToLocalStorage(toDoList){
// debugger;
localStorage.setItem('toDoList',JSON.stringify(toDoList));
renderTodos(toDoList);
}
function renderTodos(toDoList){
// debugger;
ulTasks.innerHTML = '';
toDoList.forEach(function(valInputNewTask2,index){
console.log(index);
const checked = toDoList.completed ? 'checked': null;
let currentTasks = document.createElement('li');
currentTasks.id = valInputNewTask2.id;
currentTasks.setAttribute('style','display:flex;background-color:#519872;width:100%;border-radius:7px;margin:0 0 10px 0;padding:6px 4px 6px 4px;min-height:3em;box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;');
currentTasks.innerHTML = '<input id='+index+' type = "checkbox" class="checkInactive"><div style="display:flex;flex-direction:column;flex-grow:2;"><span style="margin-left:2em;">'+valInputNewTask2.content+'</span><span style="margin-left:2em;color:#17301C;">'+valInputNewTask2.date+'</span></div><div class="clear"><span class="material-icons">clear</span></div>';
if(valInputNewTask2.completed === true){
currentTasks.classList.add('checkActive');
currentTasks.firstChild.checked = true;
}
document.getElementById('parentList').appendChild(currentTasks);
});
list_container.style.display = "block";
}
function getFromLocalStorage(){
const getReference = localStorage.getItem('toDoList');
if(getReference){
document.querySelector('.notes').style.display = 'none';
toDoList = JSON.parse(getReference);
renderTodos(toDoList);
}
}
function showModal(){
document.getElementById('myDropdown').classList.toggle('show');
}
getFromLocalStorage();
function toggle(id){
toDoList.forEach(function(item){
if(item.id == id){
item.completed = !item.completed;
}
});
addToLocalStorage(toDoList);
}
function deleteToDo(id){
debugger
// alert(id);
toDoList = toDoList.filter(function(getTask){
return getTask.id != id;
});
addToLocalStorage(toDoList);
}
debugger;
ulTasks.addEventListener('click',function(event){
debugger;
if(event.target.type === 'checkbox'){
toggle(event.target.parentElement.getAttribute('id'));
}
if(event.target.parentElement.classList.contains('clear')){
debugger;
deleteToDo(event.target.parentElement.parentElement.getAttribute('id'));
}
});
//Close the dropdown if the user clicks outside it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var myDropdown = document.getElementById("myDropdown");
if (myDropdown.classList.contains('show')) {
myDropdown.classList.remove('show');
}
}
}
//Drop down Events
document.getElementById("myDropdown").addEventListener('click',function(event){
debugger;
if(event.target.localName === 'span'){
alert(event.target.id);
}
});
I don't know about the animations but at least for the filtering:
Ideally you should be using the select html element to create a dropdown menu and use the value attribute of the option elements to perform actions when an option is selected. Read more here: https://www.w3schools.com/tags/tag_select.asp
In your case, we can use the text inside the span tag, instead of the id to see which option was selected and render the todos based on the selected option.
We can then use the JS ES6 array function .filter(item => condition), which loops over the items in the array and returns a new array with all the items that match the provided condition.
document.getElementById('myDropdown').addEventListener('click', function(event) {
if (e.target.localName === 'span'){
let selectedOption = e.target.innerText;
if(selectedOption === 'All Tasks')
renderToDos(toDoList); // render everything
else if(selectedOption === 'Active'){
let activeToDos = toDoList.filter(todo => todo.completed === false);
renderToDos(activeToDos); // only render the todos which have not been completed
}
else if(selectedOption === 'Completed'){
let completedToDos = toDoList.filter(todo => todo.completed === true);
renderToDos(completedToDos); // only render the todos which have not been completed
}
}
});
i'm working on my simple to-do app (it is possible to add tasks to list, remove it and search and filter it).
I have one problem, because when i write something in search input everything is fine (filtering works well). But when i remove letters (backspace) or remove all text i have empty list without tasks.
Could you improve my code?
Here is my code:
const addInput = document.querySelector('.add input');
const searchInput = document.querySelector('.search input');
const addButton = document.querySelector('.add button');
const ul = document.querySelector('ul');
const taskNumber = document.querySelector('h1 span');
let tasks = 0;
const addTask = (e) => {
e.preventDefault();
tasks++;
let task = addInput.value;
if (task === '') return;
const li = document.createElement('li');
li.innerHTML = task + " <button> X </button>"
ul.appendChild(li);
// console.log(task);
addInput.value = '';
taskNumber.textContent = tasks;
li.querySelector('button').addEventListener('click', deleteTask);
}
const searchTask = (e) => {
const text = e.target.value.toLowerCase();
let lis = [...document.querySelectorAll('li')];
lis = lis.filter(li => li.textContent.toLowerCase().includes(text));
ul.textContent = '';
lis.forEach(li => ul.appendChild(li));
}
const deleteTask = (e) => {
e.target.parentNode.remove();
tasks--;
taskNumber.textContent = tasks;
}
addButton.addEventListener('click', addTask)
searchInput.addEventListener('input', searchTask);
<!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>To-do app</title>
</head>
<body>
<form class="add" action=''>
<input type="text">
<button>Add</button>
</form>
<h1>Numbers of tasks: <span>0</span></h1>
<ul></ul>
<form class="search" action=''>
<input type="search" placeholder="search">
</form>
</body>
The problem is that you're overwriting the content of the ul with ul.textContent = '';
A quick way to do this is to have a .hidden class in your css, add it to the lis if they don't match the search input to hide unmatching results :
const addInput = document.querySelector('.add input');
const searchInput = document.querySelector('.search input');
const addButton = document.querySelector('.add button');
const ul = document.querySelector('ul');
const taskNumber = document.querySelector('h1 span');
let tasks = 0;
const addTask = (e) => {
e.preventDefault();
tasks++;
let task = addInput.value;
if (task === '') return;
const li = document.createElement('li');
li.innerHTML = task + " <button> X </button>"
ul.appendChild(li);
// console.log(task);
addInput.value = '';
taskNumber.textContent = tasks;
li.querySelector('button').addEventListener('click', deleteTask);
}
const searchTask = (e) => {
const text = e.target.value.toLowerCase();
let lis = [...document.querySelectorAll('li')];
// lis = lis.filter(li => li.textContent.toLowerCase().includes(text));
// ul.textContent = '';
lis.forEach(li => li.textContent.toLowerCase().includes(text) ? li.classList.remove('hidden') : li.classList.add('hidden'));
}
const deleteTask = (e) => {
e.target.parentNode.remove();
tasks--;
taskNumber.textContent = tasks;
}
addButton.addEventListener('click', addTask)
searchInput.addEventListener('input', searchTask);
.hidden {
display: none;
}
<!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>To-do app</title>
</head>
<body>
<form class="add" action=''>
<input type="text">
<button>Add</button>
</form>
<h1>Numbers of tasks: <span>0</span></h1>
<ul></ul>
<form class="search" action=''>
<input type="search" placeholder="search">
</form>
</body>
Or, have an array of elements where you would add the new li, remove it from that array on deletion, and use it to filter the results on search :
const addInput = document.querySelector('.add input');
const searchInput = document.querySelector('.search input');
const addButton = document.querySelector('.add button');
const ul = document.querySelector('ul');
var elements = [];
const taskNumber = document.querySelector('h1 span');
let tasks = 0;
const addTask = (e) => {
e.preventDefault();
tasks++;
let task = addInput.value;
if (task === '') return;
const li = document.createElement('li');
li.innerHTML = task + " <button id=" + tasks + "> X </button>"
li.id = tasks;
ul.appendChild(li);
// console.log(task);
addInput.value = '';
taskNumber.textContent = tasks;
li.querySelector('button').addEventListener('click', (e) => deleteTask(e, tasks));
elements.push(li);
}
const searchTask = (e) => {
const text = e.target.value.toLowerCase();
let lis = [...document.querySelectorAll('li')];
lis = elements.filter(li => li.textContent.toLowerCase().includes(text));
ul.textContent = '';
lis.forEach(li => ul.appendChild(li));
}
const deleteTask = (e, id) => {
e.target.parentNode.remove();
elements = elements.filter(el => {
return +el.id !== id;
})
tasks--;
taskNumber.textContent = tasks;
}
addButton.addEventListener('click', addTask)
searchInput.addEventListener('input', searchTask);
.hidden {
display: none;
}
<!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>To-do app</title>
</head>
<body>
<form class="add" action=''>
<input type="text">
<button>Add</button>
</form>
<h1>Numbers of tasks: <span>0</span></h1>
<ul></ul>
<form class="search" action=''>
<input type="search" placeholder="search">
</form>
</body>