Delete item from the localStorage after a click method - javascript

I'm trying to delete item's from a todo list that I saved in the localStorage.
I was thinking about doing something similar to this:
let deleteTodos = () => {localStorage.removeItem(todos["hola"]); };
In this part of the code :
list.addEventListener("click", (e) => {
if (e.target.classList.contains("delete")) {
e.target.parentElement.remove();
localStorage.setItem("todos", JSON.stringify(todos));
}
});
And here is the whole code to give you and idea of the whole app
const addForm = document.querySelector(".add");
const list = document.querySelector(".todos");
const search = document.querySelector(".search input");
var todos = [];
var todosString = localStorage.getItem("todos");
var todos = JSON.parse(todosString);
// generate new toDo's
const generateTemplate = (todos) => {
let html = ` <li class="list-group-item d-flex justify-content-between align-items-center">
<span>${todos}</span><i class="far fa-trash-alt delete"></i>
</li>`;
list.innerHTML += html;
};
todos.forEach((todo) => generateTemplate(todo));
// submit the todo
addForm.addEventListener("submit", (e) => {
e.preventDefault();
let todo = addForm.add.value.trim();
if (todo.length) {
todos.push(todo);
localStorage.setItem("todos", JSON.stringify(todos));
generateTemplate(todo);
addForm.reset();
}
});
// delete todo's
list.addEventListener("click", (e) => {
if (e.target.classList.contains("delete")) {
e.target.parentElement.remove();
localStorage.setItem("todos", JSON.stringify(todos));
}
});
// filter the toDo's
const filterTodos = (term) => {
Array.from(list.children)
.filter((todo) => !todo.textContent.toLowerCase().includes(term))
.forEach((todo) => todo.classList.add("filtered"));
Array.from(list.children)
.filter((todo) => todo.textContent.toLowerCase().includes(term))
.forEach((todo) => todo.classList.remove("filtered"));
};
search.addEventListener("keyup", () => {
const term = search.value.trim().toLowerCase();
filterTodos(term);
});

If you're saving the stringified todos in localStorage under "todos", you cannot then delete a single item via localStorage.removeItem(todos["hola"]).
Without commenting on whether you should be using localStorage in this way, to delete an item you'll need to replace the entire object in localStorage:
const deleteTodo = (label) => {
// get the items from storage
const oldTodos = JSON.parse(localStorage.getItem('todos'));
// delete the specified item. (however you need to do it. this might not work with your specific data structure)
const newTodos = oldTodos.filter(({ label: x }) => x === label);
// re-reserialize to local storage
localStorage.setItem('todos', JSON.stringify(newTodos));
};

Related

how to access a variable outside onClick function react

I'm trying to get list from the onClick function but I can't if there any solution, please.
here is my full code link
let abe = []
const click = (e) => {
const cityy = e.target.value
const checkUsername = obj => obj.city === cityy;
const result = abe.some(checkUsername)
if (!result) {
abe.push({ "city": cityy})
}
if (!e.target.checked) {
const indexe = abe.findIndex(p => p.city === cityy)
abe.splice(indexe, 1)
}
const simo = watch("simo")
let list = abe.map((list) => list.city).join(" , ")
}
Is the click function triggered in the first place? You have actually missed to show where the click function is used.
Here is an example. Looks like you have to store cities in the state.
const [citiesList, setCitiesList] = useState<string[]>([]);
const click = (e) => {
const cityy = e.target.value
const checkUsername = obj => obj.city === cityy;
const result = citiesList.some(checkUsername)
if (!result) {
setCitiesList(prevState => [...prevState, cityy]);
}
if (!e.target.checked) {
const cList = [...citiesList];
const indexe = cList.findIndex(p => p === cityy)
cList.splice(indexe, 1);
setCitiesList(cList);
}
const simo = watch("simo");
}

API search in javascript to return filtered list only

I am trying to make a filtered API search and only display the data(users) that has been filtered. However my search seems to return all the data and not just the data that has been filtered out. I can see the right data in the console log but can't seem to figure out how to get it to render on display.
For example, if I search for janet, I can see all the data that contains the name janet when I console log it but on display it still displays all the users. What am I doing wrong? Thanks
const UserList = document.getElementById('userList');
const searchBar = document.getElementById('searchBar');
let data = [];
searchBar.addEventListener('keyup', (e) => {
e.preventDefault();
const searchString = e.target.value;
console.log(e.target.value)
const filteredUsers = data.data.filter((user) => {
return (
user.first_name.includes(searchString) ||
user.email.includes(searchString)
);
});
console.log(filteredUsers)
displayUsers(filteredUsers);
});
const loadUsers = async () => {
try {
const res = await fetch('https://reqres.in/api/users');
data = await res.json();
displayUsers(data);
console.log(data)
} catch (err) {
console.error(err);
}
};
const displayUsers = (users) => {
const htmlString = data.data
.map((user) => {
return `
<li class="user">
<h2>${user.first_name}</h2>
</li>
`;
})
.join('');
userList.innerHTML = htmlString;
};
loadUsers();
On displayUsers function you are mapping on data.data variable. You should use users.map.
This might not be the problem, but you are defining UserList at the top and then using userList at the bottom, small typo maybe?

how to stop Checkbox from getting unchecked when page is refreshed?

So I'm creating a to-do list, and I'm saving the task to the localStorage, when I refresh the page the task stay but the checkbox gets unchecked how could I stop the checkbox from getting unchecked when I refresh the page
note: I'm creating the checkbox via js so when I add a task it creates the checkbox dynamically.
/* arry that holds tasks */
let tasks = [];
/* create a todo object */
const addTask = (text) => {
const todoTask = {
text,
checked: false,
id: Date.now(),
}
tasks.push(todoTask);
renderTodo(todoTask);
};
const formT = document.querySelector(`[data-new-todo-form]`)
const inputT = document.querySelector(`[data-new-todo-input]`)
const todoList = document.getElementById('todo-list');
formT.addEventListener('submit', e => {
e.preventDefault()
let text = inputT.value.trim();
if(text !== '') {
addTask(text);
inputT.value = '';
inputT.focus();
}
})
const renderTodo = (todoTask)=> {
localStorage.setItem('tasksRef', JSON.stringify(tasks));
const item = document.querySelector(`[data-key='${todoTask.id}']`);
if (todoTask.deleted) {
// remove the item from the DOM
item.remove();
return
}
const isChecked = todoTask.checked ? 'done': '';
const node = document.createElement('li')
node.setAttribute('class', `todo-item ${isChecked}`);
node.setAttribute('data-key', todoTask.id);
node.innerHTML = `
<input class="js-tick save-cb-state" id="${todoTask.id}" type="checkbox"/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
todoList.append(node);
if (item) {
node.replaceWith(item)
} else {
todoList.append(node)
}
}
todoList.addEventListener('click', e => {
if (e.target.classList.contains('js-tick')) {
const itemKey = e.target.parentElement.dataset.key;
toggleDone(itemKey);
}
if (e.target.classList.contains('delete')) {
const itemKey = e.target.parentElement.dataset.key;
deleteTodo(itemKey);
}
});
const toggleDone = (key) => {
const index = tasks.findIndex(task=> task.id === Number(key));
tasks[index].checked = !tasks[index].checked;
renderTodo(tasks[index]);
}
const deleteTodo = (key) => {
const index = tasks.findIndex(item => item.id === Number(key));
const todoTask = {
deleted: true,
...tasks[index]
};
tasks = tasks.filter(item => item.id !== Number(key));
renderTodo(todoTask);
}
document.addEventListener('DOMContentLoaded', () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task);
});
}
});
when you add checkbox to DOM you should set Checked attribute for that.
change renderTodo with this code:
node.innerHTML = `
<input class="js-tick save-cb-state" id="${todoTask.id}" type="checkbox" ${isChecked ? "checked" : ""}/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
if you putted your html code I could create live Demo, I think this change will be fixed your problem

How to set state of cart when no items?

In my E-Commerce project, the products are stored in localStorage. componentDidMount() gets all these products from localStorage and displays it. How to state the state or condition when no products are available.
componentDidMount = () => {
this.setProducts();
// Gets all products in cart from localStorage
this.setState(
() =>{
return {cart: JSON.parse(localStorage.getItem('myCart'))}
},
() => {
this.addTotal()
})
// How to set the condition when no products in Cart?
}
// Set all the products on Main Page
setProducts = () => {
let tempProducts = [];
storeProducts.forEach(item => {
const singleItem = {...item};
tempProducts = [...tempProducts, singleItem];
});
this.setState(() => {
return {products: tempProducts};
});
};
// Here products are added to cart and stored in localStorage
addToCart = (id) => {
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return { products: tempProducts, cart: [...this.state.cart,
product] };
},
() => {
this.addTotal();
localStorage.setItem('myCart', JSON.stringify(this.state.cart))
});
}
I have also tried to make following changes, but, no effect. In componentDidMount()
componentDidMount() {
if(this.state.cart.length > 0) {
this.setState(
() =>{
return {cart: JSON.parse(localStorage.getItem('myCart'))}
},
() => {
this.addTotal()
})
} else {
this.setState(() => {
return {cart:[]}
})
}
}
// Clear Cart
clearCart = () => {
this.setState(() => {
return {cart:[]}
}, () => {
this.setProducts();
this.addTotal();
})
localStorage.removeItem('myCart')
}
When I remove code of setState (shown in the beginning) from componentDidMount() displays empty cart message, which is expected else, if the cart is cleared and refreshed browser throws 'cart.length' error. Any possible solution?
JSON.parse will return an object. It depends on your data structure but there is no cart.lendth for the object. So that is your first problem. So for the below example, I store the parsed value as an array.
Also, if state.cart is not initiated, there is no .length property for it.
For your second problem have a look at the below version of your componentDidMount:
componentDidMount() {
if(Array.isArray(this.state.cart) && this.state.cart.length) {
const cart = localStorage.getItem('myCart') || [];
this.setState({cart: [JSON.parse(cart)]}), this.addTotal);
} else {
this.setState({ cart:[] });
}
}
Again, it depends on your implementation, but you might need to initiate the component's state with cart: localStorage.getItem('myCart') || [] or doing what I have done above. I'm basically checking if cart is an array && it has length then parse it otherwise initiate the array.
Finally I got the solution as below
const cart = localStorage.getItem('myCart')
this.setState({cart: JSON.parse(cart) ? JSON.parse(cart) : []}, this.addTotal)
Just modified the code and works perfectly without any issues

Remove an array item nested inside of an object

I'm trying to remove a specific item from an objects array based on the title attribute in the array. I keep running into a problem where I can view the array item, but I'm not able to splice the item out of the array based on the parameters entered in my remove function. I'm just getting the error message back from my else statement in the function.
I've tried using find, forEach, findIndex and match that case in order to test out removing the result based on the index, or the text value of the key 'text'. I commented out all of the functions I tried prior to searching for the answer in the forum recommendations. All of my recipe functions are working, along with my createIngredient function, which adds an object to the recipe array. But the removeIngredient function I've been trying to get to work, isn't because of the problems mentioned above.
let recipes = []
// Read existing recipes from localStorage
const loadRecipes = () => {
const recipesJSON = localStorage.getItem('recipes')
try {
return recipesJSON ? JSON.parse(recipesJSON) : []
} catch (e) {
return []
}
}
// Expose recipes from module
const getRecipes = () => recipes
const createRecipe = () => {
const id = uuidv4()
const timestamp = moment().valueOf()
recipes.push({
id: id,
title: '',
body: '',
createdAt: timestamp,
updatedAt: timestamp,
ingredient: []
})
saveRecipes()
return id
}
// Save the recipes to localStorage
const saveRecipes = () => {
localStorage.setItem('recipes', JSON.stringify(recipes))
}
// Remove a recipe from the list
const removeRecipe = (id) => {
const recipeIndex = recipes.findIndex((recipe) => recipe.id === id)
if (recipeIndex > -1) {
recipes.splice(recipeIndex, 1)
saveRecipes()
}
}
// Remove all recipes from the recipe array
const cleanSlate = () => {
recipes = []
saveRecipes()
}
const updateRecipe = (id, updates) => {
const recipe = recipes.find((recipe) => recipe.id === id)
if (!recipe) {
return
}
if (typeof updates.title === 'string') {
recipe.title = updates.title
recipe.updatedAt = moment().valueOf()
}
if (typeof updates.body === 'string') {
recipe.body = updates.body
recipe.updateAt = moment().valueOf()
}
saveRecipes()
return recipe
}
const createIngredient = (id, text) => {
const recipe = recipes.find((recipe) => recipe.id === id)
const newItem = {
text,
have: false
}
recipe.ingredient.push(newItem)
saveRecipes()
}
const removeIngredient = (id) => {
const ingredient = recipes.find((recipe) => recipe.id === id)
console.log(ingredient)
const allIngredients = ingredient.todo.forEach((ingredient) => console.log(ingredient.text))
// const recipeIndex = recipes.find((recipe) => recipe.id === id)
// for (let text of recipeIndex) {
// console.log(recipdeIndex[text])
// }
// Attempt 3
// if (indexOfIngredient === 0) {
// ingredientIndex.splice(index, 1)
// saveRecipes()
// } else {
// console.log('error')
// }
// Attempt 2
// const recipe = recipes.find((recipe) => recipe.id === id)
// const ingredients = recipe.todo
// // let newItem = ingredients.forEach((item) => item)
// if (ingredients.text === 'breadcrumbs') {
// ingredients.splice(ingredients, 1)
// saveRecipes()
// }
// Attempt 1
// const ingredientName = ingredients.forEach((ingredient, index, array) => console.log(ingredient, index, array))
// console.log(ingredientName)
// const recipeIndex = recipes.findIndex((recipe) => recipe.id === id)
// if (recipeIndex > -1) {
// recipes.splice(recipeIndex, 1)
// saveRecipes()
// }
}
recipes = loadRecipes()
OUTPUT
{id: "ef88e013-9510-4b0e-927f-b9a8fc623450", title: "Spaghetti", body: "", createdAt: 1546878594784, updatedAt: 1546878608896, …}
recipes.js:94 breadcrumbs
recipes.js:94 noodles
recipes.js:94 marinara
recipes.js:94 meat
recipes.js:94 ground beef
recipes.js:94 milk
So I'm able to view the output I printed above and see each item in the ingredients array, but trying to splice the item based on the index number or key is not working for me with the functions I have already tried and the info I have found on Stackoverflow about objects, arrays and the splice method so far.
If I am understanding correctly (after reading the commented out attempts in your code), you are trying to remove the "breadcrumbs" ingredient from the recipe that corresponds to the id passed to the removeIngredient() function.
In that case, perhaps you could take a slightly different approach to removing the ingredient from the recipes todo array, via the Array#filter method?
You could use filter() in the following way to "filter out" (ie remove) the "breadcrumbs" ingredient from the todo array via the following filter logic:
// Keep any ingredients that do not match ingredient (ie if ingredient
// equals "breadcrumbs")
todo.filter(todoIngredient => todoIngredient !== ingredient)
You might consider revising your removeIngredient() function by;
adding an additional ingredient parameter to the function arguments. This allows you to specify the ingredient to be removed from the recipe corresponding to recipeId
and, introducing the filter() idea as described:
const removeIngredient = (recipeId, ingredient) => {
const recipe = recipes.find(recipe => recipe.id === recipeId)
if(recipe) {
// Filter recipe.todo by ingredients that do not match
// ingredient argument, and reassign the filtered array
// back to the recipie object we're working with
recipe.todo = recipe.todo.filter(todoIngredient =>
(todoIngredient !== ingredient));
}
}
Now, when you introduce the "remove" button for each ingredient, you would call the removeIngredient() as follows:
var recipeId = /* got id from somewhere */
var ingredientText = /* got ingredient from somewhere */
removeIngredient( recipeId, ingredientText );
Hope this helps!

Categories

Resources