Vanilla JS budget app every item added adds previous item from Array - javascript

When a user enters a title and amount, it gets pushed to an array. If the item is an expense, it gets pushed to an expense array of objects, if it's an income, it gets pushed to an income array of objects. Then either the displayIncome or displayExpense functions render a component so that it's displayed. The issue that i'm having is that every time I press the submit button, the app displays the previous item as one item and also the previous item with the new item as another individual item. If there are two items in the array, the app will display (item1) ((item1) + (item2)). The picture shows my issue. How do I get the app to only display one item for each item in the array?
let expense_list = []
let income_list = []
addExpense.addEventListener('click', () =>{
if(expenseTitle.value == '' || expenseAmount.value == ''){
return;
}
let expense = {
type: 'expense',
title: expenseTitle.value,
amount: expenseAmount.value,
id: Date.now()
}
expense_list.push(expense)
console.log(expense_list)
clearExpense()
displayExpense()
})
addIncome.addEventListener('click', () =>{
if(incomeTitle.value == '' || incomeAmount.value == ''){
return;
}
let income = {
type: 'income',
title: incomeTitle.value,
amount: incomeAmount.value,
id: Date.now()
}
income_list.push(income)
console.log(income_list)
clearIncome()
displayIncome()
})
const clearExpense = () =>{
expenseTitle.value = '';
expenseAmount.value = '';
}
const clearIncome = () =>{
incomeTitle.value = ''
incomeAmount.value = ''
}
const displayExpense = () =>{
expense_list.map((entry) =>{
return expenseList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
})
}
const displayIncome = () =>{
income_list.map((entry) =>{
return incomeList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
})
}
I've tried just using one array for expenses and incomes, and using forEach but every time I get the same result.

Clear the expenseList.innerHTML before mapping.
Something like that
const displayExpense = () =>{
expenseList.innerHTML = ''
expense_list.map((entry) =>{ ....

Related

Svelte variable not updating from localStorage without using setInterval and forcing it

I have an app that stores items into locations in localStorage and then displays the items in HTML.
One of the reasons i wanted to use Svelte was for reactive variables, but whenever I attempt to use a reactive variable that changes whenever localStorage.current_items changes, the ItemList variable doesn't change.
The only way I could get it to work is by using setInterval but that is not a great way to do it. How can I make it so that ItemList changes properly when the localStorage.current_items string changes.
<script lang="ts">
import {
getData,
createItem,
createLocation,
closeItem,
} from './lib/database.js';
import LocationSelector from './lib/LocationSelector.svelte';
import { flip } from 'svelte/animate';
import { writable } from 'svelte/store';
let DB = getData();
// load items from localstorage.items
let ItemList = [];
let Location;
setInterval(() => {
Location = localStorage.current_items;
ItemList = JSON.parse(localStorage.current_items).items;
}, 500);
console.log(ItemList);
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(JSON.parse(Location).id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
</script>
<LocationSelector />
<div class="app">
<input
type="text"
id="newItemInput"
bind:value={newItem}
placeholder="Add a new item"
on:keydown={newItemKeyDown}
/>
<button
id="filter_showClosed"
data-active="false"
on:click={function () {
filter_showClosed = !filter_showClosed;
let el = document.getElementById('filter_showClosed');
if (filter_showClosed) {
el.innerHTML = 'Hide closed';
el.dataset.active = 'true';
} else {
el.innerHTML = 'Show closed';
el.dataset.active = 'false';
}
}}>Show closed</button
>
<!-- <button
id="deleteClosed"
on:click={function () {
let it = items;
for (let i = 0; i < it.length; i++) {
if (it[i].closed == true) {
it.splice(i, 1);
}
}
items = it;
sort_items(items);
}}>Delete all closed</button
> -->
<div class="list">
{#each ItemList as item, index (item.id)}
<div class="item {item.closed}" animate:flip={{ duration: 100 }}>
{#if item.closed == false || (filter_showClosed == true && item.closed == true)}
<div>
<img
src="/up.svg"
class="item-icon"
class:closed={item.closed == true}
alt="move item up in priority"
on:click={function () {
// increaseLevel({ item });
}}
/>
{item.name} ({index})
</div>
<div>
{#if item.closed == false}
<img
src="/close.svg"
class="item-icon"
alt="close item"
on:click={function () {
console.log(Location.id);
closeItem(JSON.parse(Location).id, item.id);
}}
/>
{/if}
</div>
{/if}
</div>
{/each}
</div>
</div>
<style>
</style>
I tried using this writeable method, but that didn't work either as the variable still didn't change.
import { writable } from 'svelte/store';
const ItemList = writable([]);
let Location = {};
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(Location.id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
// Update the Location object with the current value of localStorage.current_items as an object
Location = JSON.parse(localStorage.current_items);
// Update the ItemList store with the new location's items
ItemList.set(Location.items);
You should use a store that fully wraps the access to localStorage.
Something like:
function localStorageStore(key, initial) {
const value = localStorage.getItem(key)
const store = writable(value == null ? initial : JSON.parse(value));
store.subscribe(v => localStorage.setItem(key, JSON.stringify(v)));
return store;
}
Reading and writing is just a regular store, but on initial load the value comes from the storage and on setting the value, it is also written to storage.

JavaScript :Ajax - Symfony 6 : trying to send form with plain js ajax

I have a little problem or a big one, I don't know. I'm trying to send a form with ajax with Symfony, and native JavaScript, but I don't really know how. I managed to do ajax with GET request to try to find a city (which is included in this form).
So I've got my form, I also want to send 2 arrays 1 for images (multiple images with different input) the input are created with js via CollectionType::class, then I'm putting my images in array which I want to send.
And the other array is for the city I want my product to be in. I've got an input text and via ajax it's searching city then by clicking on the city I've got a function putting it on an array.
but now I find difficulties trying to send it everything I found on the web mostly uses jQuery.. but I want to learn JavaScript so I believe I have to train with native first.
so I tried to send my form, but nothing happened when I submit it, not even an error, it just reload the page, and in my console I've got a warning for CORB issues I think it's due to my browser blocking my request because something is wrong in it?
I'm trying to find a way to send it and save it in my database.
so here's the code:
{% extends "base.html.twig" %}
{% block body %}
<div class="container">
<div class="row">
<div class="col-lg-6 mx-auto mt-5">
{{form_start(form)}}
{{form_errors(form)}}
{{form_row(form.title)}}
{{form_row(form.description)}}
{{form_row(form.surface)}}
{{form_row(form.piece)}}
{{form_row(form.type)}}
<div class="container">
<div class="select-btn">
<span class="btn-text d-flex">
<input type="text" oninput="getData(this.value)" class="rel" name="ville" id="">
<span class="arrow-dwn">
<i class="fa-solid fa-chevron-down"></i>
</span>
</span>
</div>
<ul class="list-items js-result"></ul>
</div>
<button type="button" class="btn btn-primary btn-new opacity-100" data-collection="#foo">ajouter une image</button>
<div id="foo" class="row" data-prototype="{{include ("include/_Addimage.inc.html.twig", {form: form.image.vars.prototype})|e("html_attr")}}" data-index="{{form.image|length > 0 ? form.image|last.vars.name +1 : 0}}">
{% for image in form.image %}
<div class="col-4">
{{ include ("include/_Addimage.inc.html.twig", {form: image}) }}
</div>
{{form_errors(form.image)}}
{% endfor %}
</div>
<div class="col-4 mt-5">
{{form_row(form.submit)}}
</div>
{{form_widget(form._token)}}
{{form_end(form, {render_rest: false})}}
</div>
</div>
</div>
{% endblock %}
here the code of my JavaScript, everything is in my twig file, because as you will see I added eventListener on some input, I didn't see a better way maybe someone can correct me.
{% block javascripts %}
<script type="text/javascript">
/////////////// GET INPUT TEXT VALUE AND SHOW A LIST OF CITIES
function getData(text) {
const param = new URLSearchParams();
param.append('text', text);
const url = new URL(window.location.href);
fetch(url.pathname + "?" + param.toString() + "&ajax=1", {
header: {
"X-Requested-With": "XMLHttpRequest"
}
})
.then(response => response.json())
.then(data => {
handle_result(data);
});
}
////////////////////////////// CREATE MY OPTIONS WITH CITIES NAME
function handle_result(response)
{
let result_div = document.querySelector(".js-result");
let str = "";
for (let i = response.length - 1; i >= 0; i--) {
str += "<option" + ' ' + "onclick=" + "addTag(this.value)" + ' ' + "class=" + "item" + ' ' + "value=" + response[i].ville + ">" + response[i].ville + "</option>";
}
result_div.innerHTML = str;
};
// //////////////////////////// ADD THE CITY NAME IN A CONTAINER WHEN I USER CLICK ON IT
const selectBtn = document.querySelector(".select-btn");
const rel = document.querySelector(".rel");
items = document.querySelectorAll(".item");
rel.addEventListener("click", () => {
selectBtn.classList.toggle("open");
});
function createTag(label) {
const div = document.createElement('div');
div.setAttribute('class', 'tag');
const span = document.createElement('span');
span.innerText = label;
const closeBtn = document.createElement('i');
closeBtn.setAttribute('data-item', label);
closeBtn.setAttribute('onclick', 'remove(this)');
closeBtn.setAttribute('class', 'material-icons');
closeBtn.innerHTML = 'close';
div.appendChild(span);
div.appendChild(closeBtn);
return div;
}
btnText = document.querySelector(".btn-text");
let tags = [];
function addTags()
{
reset();
for (let a of tags.slice().reverse()) {
const tag = createTag(a);
selectBtn.prepend(tag);
}
}
function addTag(value) {
input = document.querySelector('.rel');
console.log(input);
if (tags.includes(value)) {
alreadyExist(value);
}
else {
tags.shift();
tags.push(value);
addTags();
}
input.value = "";
}
function alreadyExist(value) {
const index = tags.indexOf(value);
tags = [
... tags.slice(0, index),
... tags.slice(index + 1)
];
addTags();
}
function reset() {
document.querySelectorAll('.tag').forEach(function (tag) {
tag.parentElement.removeChild(tag);
})
}
function remove(value) {
const data = value.getAttribute('data-item');
const index = tags.indexOf(data);
tags = [
... tags.slice(0, index),
... tags.slice(index + 1)
];
addTags();
}
//////////////////////////////////////////////////////// CREATING IMAGE ARRAY TO SEND WITH AJAX REQUEST ?
images = [];
function image_to_array(value) {
if(!images.includes(value))
{
images.push(value);
}else{
return false;
}
}
const form =
{
title: document.getElementById('product_form_title'),
description: document.getElementById('product_form_description'),
surface: document.getElementById('product_form_surface'),
piece: document.getElementById('product_form_piece'),
type: document.getElementById('product_form_type'),
}
const submit = document.getElementById('submit', () => {
const request = new XMLHttpRequest();
const url = new URL(window.location.href);
const requestData =
`
title=${form.title.value}&
description=${form.description.value}&
surface=${form.surface.value}&
piece=${form.piece.value}&
image=${JSON.stringify(images)}&
type=${JSON.stringify(tags)}&
ville=${tags}
`;
fetch(requestData , url.pathname ,{
header: {
"X-Requested-With": "XMLHttpRequest"
}
})
request.addEventListener('load', function(event) {
console.log(requestData);
});
request.addEventListener('error', function(event) {
console.log(requestData);
});
});
////////////////////////////// CREATE NEW FILE INPUT
const newItem = (e) => {
const collectionHolder = document.querySelector(e.currentTarget.dataset.collection);
const item = document.createElement('div');
item.classList.add('col-4');
item.innerHTML = collectionHolder.dataset.prototype.replace(/__name__/g, collectionHolder.dataset.index);
item.querySelector('.btn-remove').addEventListener('click', () => item.remove());
collectionHolder.appendChild(item);
collectionHolder.dataset.index ++;
}
document.querySelectorAll('.btn-new').forEach(btn => btn.addEventListener('click', newItem));
</script>
{% endblock %}
here my controller but I don't think it is the issue, I didn't finish it since I'm quite lost on the js part
class AdminController extends AbstractController
{
#[Route('/admin/create_product', name: 'create_product', methods: ['POST', 'GET'])]
public function createProduct(EntityManagerInterface $em, SluggerInterface $slugger, Request $request, LieuxRepository $villeRepo, SerializerInterface $serializer): Response
{
$product = new Product;
$ville = new Lieux;
$form = $this->createForm(ProductFormType::class, $product);
$form->handleRequest($request);
$list = $villeRepo->findAll();
$query =$request->get('text');
if($request->get('ajax')){
return $this->json(
json_decode(
$serializer->serialize(
$villeRepo->handleSearch($query),
'json',
[AbstractNormalizer::IGNORED_ATTRIBUTES=>['region', 'departement', 'products']]
), JSON_OBJECT_AS_ARRAY
)
);
}
if($request->isXmlHttpRequest())
{
if ($form->isSubmitted() && $form->isValid()) {
$product->setCreatedAt(new DateTime());
$product->setUpdatedAt(new DateTime());
$product->setVille($form->get('ville')->getData());
$product->setType($form->get('type')->getData());
$em->persist($product);
$em->flush();
}
}
return $this->render(
'admin/create_product.html.twig',
['form' => $form->createView() ]
);
}
hope it's clear, thank you

Element.closest() returns null on existing HTML element

For one of my study project, I have to create a cart system. On the cart.html page, the cart is supposed to be displayed. Until there, I am good.
When the user changes the quantity of one of the item, I am supposed to update it, using Element.closest().
My problem is : when I change the quantity of one of the products, the console displays null whereas it should display the correct element.
Where is the problem coming from ?
I wrote the following code :
article = document.getElementsByTagName('article'),
quantity = document.getElementsByClassName('itemQuantity');
const cartContent = getLocalStorage('totalCart');
let i = 0,
array = [],
datasetArray = [];
window.addEventListener('load', function () {
cartContent.map((element) => {
fetch(`http://localhost:3000/api/products/${element.id}`)
.then((response) => response.json())
.then((data) => {
displayContent(data, element);
convertCollectionToArray(article);
addListenerOnCollection(quantity, 'change');
});
});
});
/**
* Displays elements on cart page
* #param { Object } cart Contains fetched elements according to id stored in localStorage
* #param { Object } storageElement Contains id, color and quantity of storaged products
*/
function displayContent(cart, storageElement) {
cartItems.insertAdjacentHTML(
'beforeend',
`<article class="cart__item" data-id="${storageElement.id}" data-color="${storageElement.color}">
<div class="cart__item__img">
<img src="${cart.imageUrl}" alt="Photographie d'un canapé">
</div>
<div class="cart__item__content">
<div class="cart__item__content__description">
<h2>${cart.name}</h2>
<p>${storageElement.color}</p>
<p>${cart.price}€</p>
</div>
<div class="cart__item__content__settings">
<div class="cart__item__content__settings__quantity">
<p>Qté : </p>
<input type="number" class="itemQuantity" name="itemQuantity" id="quantity" min="1" max="100" value="${storageElement.quantity}">
</div>
<div class="cart__item__content__settings__delete">
<p class="deleteItem">Supprimer</p>
</div>
</div>
</div>
</article>`
);
}
function convertCollectionToArray(htmlCollection) {
array = Array.from(htmlCollection);
}
function getDataset(array) {
array.map((element) => {
datasetArray.push(element.dataset);
});
}
function addListenerOnCollection(collection) {
for (var index in collection) {
collection[index].onchange = function () {
updateCartQuantity(article.item(index).dataset);
};
}
}
function updateCartQuantity(dataset) {
let elementToUpdate = cartItems.closest(
`.cart__item[data-id="${dataset.id}"][data-color="${dataset.color}"]`
);
}
function getQuantity() {
let newQuantity;
for (index in quantity) {
newQuantity = quantity.item(index).value;
}
return newQuantity;
}

Why when i am searching for something else is deleting the previous contents?

Why when you are searching for something else is deleting the previous contents ?For example first you search for egg and show the contents but then when you search for beef the program deletes the egg and shows only beef.Thank you for your time code:
const searchBtn = document.getElementById('search-btn');
const mealList = document.getElementById('meal');
const mealDetailsContent = document.querySelector('.meal-details-content');
const recipeCloseBtn = document.getElementById('recipe-close-btn');
// event listeners
searchBtn.addEventListener('click', getMealList);
mealList.addEventListener('click', getMealRecipe);
recipeCloseBtn.addEventListener('click', () => {
mealDetailsContent.parentElement.classList.remove('showRecipe');
});
// get meal list that matches with the ingredients
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
let html = "";
if(data.meals){
data.meals.forEach(meal => {
html += `
<div class = "meal-item" data-id = "${meal.idMeal}">
<div class = "meal-img">
<img src = "${meal.strMealThumb}" alt = "food">
</div>
<div class = "meal-name">
<h3>${meal.strMeal}</h3>
Get Recipe
</div>
</div>
`;
});
mealList.classList.remove('notFound');
} else{
html = "Sorry, we didn't find any meal!";
mealList.classList.add('notFound');
}
mealList.innerHTML = html;
});
}
Beacuse you are using innerHTML , if you want to save the previous contents you should use append or innerHTML + = .
Because everytime you make a search, the html var is populated with new data.
if you move the 'html' variable to the root scope, this should get you there:
// get meal list that matches with the ingredients
let html = ""; // <-- place it outside the function body
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
// let html = ""; // <-- remove it from here
if(data.meals){
data.meals.forEach(meal => {

Update localStorage value (todo list)

I am doing a task list with an editable function for the each task item. What I expect is that when I update item's value, the value in LocalStorage update simultaneously. Currently, the value in LocalStorage can be updated, however, it only updates the last value of it no matter which item's value I modify. And the one should be changed does not be modified. How do I change correct localStorage value when I revise the task item?
const todo__input = document.querySelector(".todo__input")
const add__btn = document.querySelector(".add__btn")
const item__sector = document.querySelector(".item__sector")
function createToDoItem(toDoItem) {
const position = "beforeend"
const item = `
<div class="item">
<input type="checkbox" class="done__btn">
<input type="text" class="item__content" value="${toDoItem}" disabled>
<button class="edit__btn"><i class="far fa-edit"></i></button>
<button class="delete__btn"><i class="far fa-trash-alt"></i></button>
</div>
`
item__sector.insertAdjacentHTML(position, item)
return item__sector
}
// load todo item from localstorage when page is loaded
document.addEventListener("DOMContentLoaded", getLocalStorage)
// add item to the item sector
add__btn.addEventListener("click", e => {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
})
// keypress Enter
document.addEventListener("keypress", e => {
if (e.keyCode == 13) {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
}
})
// the function on item (done, edit, and delete)
item__sector.addEventListener("click", e => {
const parent = e.target.parentElement
// done
if (e.target.classList.contains("done__btn")) {
e.target.nextElementSibling.classList.toggle("done__color")
}
// edit the todo item
if (e.target.classList.contains("edit__btn")) {
if (e.target.previousElementSibling.disabled.disabled == true) {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
} else {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
e.target.previousElementSibling.setAttribute("value", e.target.previousElementSibling.value)
editLocalStorage(e.target.previousElementSibling)
}
}
// delete todo item
if (e.target.classList.contains("delete__btn")) {
parent.remove()
deleteLocalStorage(e.target.previousElementSibling.previousElementSibling)
}
})
// function for check todo status in the LocalStorage
function checkLocalStorage() {
let todos
if (localStorage.getItem("todos") === null) {
todos = []
} else {
todos = JSON.parse(localStorage.getItem("todos"))
}
return todos
}
// function for save localstorage
function saveLocalStorage(todo) {
const todos = checkLocalStorage()
todos.push(todo)
localStorage.setItem("todos", JSON.stringify(todos))
}
// function for get item and render to the screen from localstorage
function getLocalStorage() {
const todos = checkLocalStorage()
todos.forEach(todo => {
createToDoItem(todo)
})
}
// edit localStorage
function editLocalStorage(todo) {
const todos = checkLocalStorage()
const todoIndex = todo.getAttribute("value")
todos.splice(todos.indexOf(todoIndex), 1, todoIndex)
localStorage.setItem("todos", JSON.stringify(todos))
}
====
<body>
<div class="container">
<h1 class="title">My To-Do List</h1>
<form class="add__todo">
<input type="text" class="todo__input" placeholder="Add a task...">
<button class="add__btn">Add</button>
</form>
<div class="item__sector">
</div>
<div class="item__status">
<button class="all">All</button>
<button class="completed">COMPLETE</button>
<button class="incompleted">UNCOMPLETE</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
<script src="app.js"></script>
</body>
The reason that causes your solution to edit the last value is:-
The todoIndex variable inside the editLocalStorage function is referencing the new updated value from your input which is not yet stored inside the todos array in local storage therefore indexOf() returns -1 hence editing the last value.
I have rewritten the JS with a tweak to the functions item__sector.addEventListener, editLocalStorage and added a global variable edit__index
Code Snippet
const todo__input = document.querySelector(".todo__input")
const add__btn = document.querySelector(".add__btn")
const item__sector = document.querySelector(".item__sector")
let edit__index = -1
function createToDoItem(toDoItem) {
const position = "beforeend"
const item = `
<div class="item">
<input type="checkbox" class="done__btn">
<input type="text" class="item__content" value="${toDoItem}" disabled>
<button class="edit__btn"><i class="far fa-edit"></i></button>
<button class="delete__btn"><i class="far fa-trash-alt"></i></button>
</div>
`
item__sector.insertAdjacentHTML(position, item)
return item__sector
}
// load todo item from localstorage when page is loaded
document.addEventListener("DOMContentLoaded", getLocalStorage)
// add item to the item sector
add__btn.addEventListener("click", e => {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
})
// keypress Enter
document.addEventListener("keypress", e => {
if (e.keyCode == 13) {
e.preventDefault()
const input__value = todo__input.value
if (input__value.trim() === "") { return }
createToDoItem(input__value)
saveLocalStorage(input__value)
todo__input.value = ""
}
})
// the function on item (done, edit, and delete)
item__sector.addEventListener("click", e => {
const parent = e.target.parentElement
// done
if (e.target.classList.contains("done__btn")) {
e.target.nextElementSibling.classList.toggle("done__color")
}
// edit the todo item s
if (e.target.classList.contains("edit__btn")) {
if (e.target.previousElementSibling.disabled.disabled == true) {
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
} else {
const todos = checkLocalStorage()
if (edit__index === -1) {
const valueBeforeEdit = e.target.previousElementSibling.getAttribute("value")
edit__index = todos.indexOf(valueBeforeEdit)
} else {
const valueAfterEdit = e.target.previousElementSibling.value
editLocalStorage(edit__index, valueAfterEdit)
edit__index = -1
}
e.target.previousElementSibling.disabled = !e.target.previousElementSibling.disabled
e.target.previousElementSibling.setAttribute("value", e.target.previousElementSibling.value)
}
}
// delete todo item
if (e.target.classList.contains("delete__btn")) {
parent.remove()
deleteLocalStorage(e.target.previousElementSibling.previousElementSibling)
}
})
// function for check todo status in the LocalStorage
function checkLocalStorage() {
let todos
if (localStorage.getItem("todos") === null) {
todos = []
} else {
todos = JSON.parse(localStorage.getItem("todos"))
}
return todos
}
// function for save localstorage
function saveLocalStorage(todo) {
const todos = checkLocalStorage()
todos.push(todo)
localStorage.setItem("todos", JSON.stringify(todos))
}
// function for get item and render to the screen from localstorage
function getLocalStorage() {
const todos = checkLocalStorage()
todos.forEach(todo => {
createToDoItem(todo)
})
}
// edit localStorage
function editLocalStorage(editIndex, editValue) {
const todos = checkLocalStorage()
todos.splice(editIndex, 1, editValue)
localStorage.setItem("todos", JSON.stringify(todos))
debugger
}
Note:
There is an edge case of having more than one todo item with the same value that you need to solve for.

Categories

Resources