Problem using splice method, always delete the first item - javascript

I'm having a problem removing an item from a "cart". Each time i'm clicking on delete, it's deleting the right element from the DOM, but it's always deleting the first element from my array/localStorage. I know the problem is in my splice method, but i have literally no idea about what to do.
If more informations are required, i can provide the github it's located on
Thanks in advance
let cartItms = JSON.parse(localStorage.getItem("Cart"));
let productId = JSON.parse(localStorage.getItem("productId"));
let optionSelected = JSON.parse(localStorage.getItem('Lense'));
let totalPrice = 0;
const shoppingCart = document.querySelector('.cart__content--items');
function deleteProduct() {
shoppingCart.addEventListener('click', (e) => {
e.preventDefault();
//Remove item from cart
if(e.target.classList[0] === "cart__content--item__delete") {
e.target.parentElement.parentElement.remove();
cartItms.splice(e.target,1);
productId.splice(e.target,1);
optionSelected.splice(e.target,1);
localStorage.setItem('Cart', JSON.stringify(cartItms));
localStorage.setItem('productId', JSON.stringify(productId));
localStorage.setItem('Lense', JSON.stringify(optionSelected));
}
//Recalculate the price of current cart
totalPrice = 0;
cartItms.forEach((data) => {
totalPrice += data.price/100;
})
document.querySelector('.cart-content').innerHTML = '('+ cartItms.length +')';
document.querySelector('.total-price').innerHTML = totalPrice + "€";
})
}

Assuming cartItms is an array, then you can use.
cartItms.shift();
The shift() method removes the first element from an array and returns
that removed element. This method changes the length of the array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift

Related

Trying to create a delete button function that deletes specific item in array in javascript

I'm just learning javascript and I'm trying to build a To-Do-List app. Using the render function, I render the myList values to the screen after pushing the input values into the myList array.
My problem is creating a deleteButton function that deletes a specific item in the array. A delete button appears right next to entered values on the screen, and when the user clicks on it, that specific item in the array should be deleted. Any advice on how to solve this?
let myList = []
const submitBtn = document.getElementById("submit-btn");
const clearListBtn = document.getElementById("clearList-btn");
const inputEl = document.getElementById("input-btn");
const olEl = document.getElementById("ol-el");
const doneBtn = document.getElementById("done-btn");
function render(leads) {
let listItems = " ";
for ( let i = 0; i < leads.length; i++) {
listItems +=
`<li id = " ">
${leads[i]} <button id= "done-btn" onclick = "deleteButton(${leads[i]})">X</button>
</li>
`;
}
olEl.innerHTML = listItems;
}
submitBtn.addEventListener("click", function() {
myList.push(inputEl.value);
inputEl.value = " ";
render(myList);
})
clearListBtn.addEventListener("click", function() {
myList = [];
render(myList)
})
function deleteButton(value) {
myList.remove(value);
render(myList);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="box">
<p>To-Do List</p>
<input value = "Add an item!" id = "input-btn">
<button id = "submit-btn">submit</button>
<button id = "clearList-btn">clear list</button>
<ol id="ol-el"></ol>
<script src = "index.js"></script>
</div>
</body>
</html>
use Array.splice with the selected item's index, you won't need to pass in the whole item.
so the on click call would be:
onclick = "deleteButton(${i})"
and the function:
function deleteButton(index) {
myList.splice(index, 1); // deletes one item starting from 'index'
render(myList);
}
for more details on Array.splice - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
This is how I would do it:
Loop through your array and get the index of the item you need to remove using the indexOf method.
Pass the index into the splice method thereby removing that element from the array
Like this:
// Loop through your array
toDoList.forEach(item => {
// Listen for a click on your button element
button.addEventListener('click', () => {
let index = toDoList.indexOf(item) // This tells you the position of the item you want to remove
if (index > -1) { // Make sure the array is not empty
toDoList.splice(index, 1); // This removes the item from the array
}
})
}
Hope this was somehow helpful :)
The function below accepts an id to compare all objects in the array against. NOTE: This method will create a new array that you would have to assign to your variable which I marked with setSortedData()
This functions by utilizing the built in .filter() method for arrays. Essentially I filter out all elements that are the given element by saying keep every element that is not the id.
const deleteItem = (id) => {
const arr = sortedData.filter((item) => item.id !== id);
setSortedData(arr);
};
To remove an element from an existing array use .splice().

equating last value in loop problem in innerHtml

forecasts is array who has a 10 elements when ı try to print its work perfectly when ı use innerHtml its giving the last value of items and everything is look same
const getOtherDays = (data) => {
data.forecasts.forEach((forecast)=>{
for(var i = 0; i < day.length; i++) {
items = forecast.day;
console.log(items)
day[i].innerHTML = `${items}`
}
})
}
You shouldn't use a nested loop. If each element of data.forecasts is for a different day, use the index in that array to assign to the corresponding DOM element.
const getOtherDays = (data) => {
data.forecasts.forEach((forecast, i) => {
items = forecast.day;
console.log(items)
day[i].innerHTML = `${items}`
})
}
You are looping over the elements and setting it to the forecast of the day on every one. You want to select the specific element. The forEach index has the index. Hopefully that index matches the day in your elements. Basic idea:
const getOtherDays = (data) => {
data.forecasts.forEach((forecast, index)=>{
items = forecast.day;
day[index].innerHTML = `${items}`;
})
}

JS: Removing from local storage / hiding button text

Evening folks.
Trying to wrap up my to do list and I'm not able to remove items from localStorage without either deleting everything from using the wrong key or the contents just re-appearing on page refresh. A second smaller issue is that button text is merging into the innerText, like it's supposed to, but I can't find a way to exclude it It is currently commented out, if I don't then it breaks the previous entry. I've left my most recent, and rather poor attempt, below but otherwise, the rest appears to be working.
Not sure if it's ok to attach the whole code, but here it is below.
const todoForm = document.querySelector('#todoForm');
const todoList = document.querySelector('#todoList');
let todoItem = document.querySelector('#todoItem');
// const todo = JSON.parse(localStorage.getItem('todo'));
// Pull from storage
const savedList = JSON.parse(localStorage.getItem('todo')) || [];
for (let i = 0; i < savedList.length; i++) {
const newTodo = document.createElement('li');
newTodo.innerText = savedList[i].item;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.isCompleted = savedList[i].isCompleted ? true : false;
if(newTodo.isCompleted) {
newTodo.style.textDecoration = 'line-through';
}
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
}
// Add Item and Remove Button
todoForm.addEventListener('submit', function(e){
e.preventDefault();
const newTodo = document.createElement('li');
const newItem = document.querySelector('#todoItem').value;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.innerText = newItem;
newTodo.setAttribute('id', itemId.id);
newTodo.isCompleted = false;
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
todoForm.reset();
// Save to storage
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
localStorage.setItem('todo', JSON.stringify(savedList));
});
// Strike Through Item
todoList.addEventListener('click', function(e){
let clickListItem = e.target;
if (!clickListItem.isCompleted){
clickListItem.style.textDecoration = 'line-through';
clickListItem.isCompleted = true;
} else {
clickListItem.style.textDecoration = 'none';
clickListItem.isCompleted = false;
}
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
});
// Remove from storage
todoList.addEventListener('click', function(e){
let removeItem = e.target;
const taskId = e.target.id;
if (e.target.tagName === 'BUTTON'){
e.target.parentNode.remove();
removeFunc(taskId);
}
});
function removeFunc(taskId){
for (let i = 0; i < savedList.length; i++){
const key = savedList[i].id;
if(key === taskId.id){
localStorage.removeItem(key);
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
}
Thanks for any insight.
My first guess looking at this would be the that, since the IDs are being defined by Date.getTime() being called at two different times, that those IDs are not the same. I would suggest that, when you push to savedList at the end of the function to add an item, that you set id as newItem.id, like you for the item name, rather than calling getTime() again
I do see few problems in your code. Here we go.
Remove text reappears because on adding an item, you create todo object with item value set to newTodo.innerText, if you check your saved value in the localstorage it holds extra Remove in it, that's because innerText gets the text of elements under newTodo (in our case we have a button in there). As a fix, you just need to set the actual value from the textbox and not the innerText. You already have that stored in a variable called newItem
And yes, as like #cfinn16 pointed it out, the id we save here would be in number format, when you compare the id from remove button attribute with the id from the savedList array you will see a mismatch. As a resolution, you can convert getTime().toString().
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
Deleting an item, not actually removing the item from both in-memory array i.e savedList or from the localStorage. All we want to do it, just get the taskId, filter/remove items from savedList then replace it in the localStorage with same key. But on loading each todoItems on page refresh, you set new date as the value to each todoItems but that should be the value from the localstorage itself.
let itemId = { id: new Date().getTime() };
Strikethrough an item, has a similar problem. Here you are trying to find clicked item from the array using text instead we can use the id itself.
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
Solution:
https://codepen.io/renishb10/project/editor/ANyqqo
Let me know if you've any questions.
With the help from Renish, I've modified to include the follow and posting it here so it may help anyone else.
// Save to storage
savedList.push({ item: newItem, isCompleted: false, id: new Date().getTime().toString() });
localStorage.setItem('todo', JSON.stringify(savedList));
Changed the new Date() to a string. As both Renish and cfinn pointed out I had mismatch .id. Changing newTodo to newItem go around my innerText from the button being carried over.
// Pull from Storage
newButton.innerText = 'Remove';
newButton.setAttribute('id', savedList[i].id);
Modified my pull from storage code to reflect the new button .id.
function removeFunc(taskId){
splicedList = savedList.filter(l => l.id != taskId)
localStorage.setItem('todo', JSON.stringify(splicedList));
}
Used a filter instead to find the items to remove, based on the .id.
Github of the full modified code:
https://github.com/BreadsticksN7/collections/blob/20b679fc704d05af5576faa3963f676c0bd2665e/todolist.js
Thanks to everyone and their assistance.

Why does findIndex() return 0, instead of the desired index?

I've been stuck trying to figure out how to retrieve a desired index. I have a user adding names to a Guestlist, with the option to remove names. All the names are appended to an array saved to localStorage. When the delete button is clicked, I want to iterate over the array, find the matching string and retrieve it's index. All I'm getting however, is a -1 if the string doesn't match, and 0 if it matches. Where is my error? Any help is appreciated.
deleteBtn.addEventListener('click', function () { // Makes the Delete button active.
const deleteName = this.parentElement.innerText; // parent element is li
const test = localStorage.getItem('data');
const testParsed = JSON.parse(test);
for (let i = 0; i < testParsed.length; i++) {
let compare = `Name: ${testParsed[i].name}, About: ${testParsed[i].about}Delete entry`; // matches innerHtml of deleteName
compare.replace('.,:', ''); // Removes unwanted punctuation
console.log('Compare: ', compare);
function index(){
return deleteName === compare;
}
console.log(testParsed.findIndex(index));
I played around some more, and figured it out. I'll leave the question up in case someone else can make use of it.
deleteBtn.addEventListener('click', function () { // Makes the Delete button active.
const deleteName = this.parentElement.innerText; // parent element is li
const test = localStorage.getItem('data');
const testParsed = JSON.parse(test);
console.log(test);
for (let i = 0; i < testParsed.length; i++) {
let compare = `Name: ${testParsed[i].name}, About: ${testParsed[i].about}Delete entry`; // matches innerHtml of deleteName
compare.replace('.,:', ''); // Removes unwanted punctuation
console.log('Compare: ', compare);
if(deleteName === compare) {
function index(equals) { // compare is string, equals is object
return equals.name === testParsed[i].name && equals.about === testParsed[i].about;
}
console.log(testParsed.findIndex(index));
}

Click on an element and delete it from an array

itemElement.onclick=function(){
//remove element from view
this.parentNode.removeChild(this);
//find the element that was clicked on in the array
//which should be itemElement(aka this)????
var index=itemArray.indexOf(this);
//remove it from the array
itemArray.splice(index,1);
//console.log to check
console.log(itemArray);
}
That is my code I am currently using to delete items from a list. I want the user to be able to click on the item in their list they want to delete, delete it from the view and then delete it from an array of items. Deleting the element from the view is working fine, but for some reason its only deleting the last element added to the array, not the actual element that was clicked on. So if the user makes a list that has Bob,Tom,Rob and then clicks on Tom, Tom is no longer displayed in the list but Rob will be deleted from the array.
Here is that whole block of code
const addButton =<HTMLButtonElement>document.querySelector("#addButton");
const saveButton = document.querySelector("#saveButton");
const itemsSection = document.querySelector("#itemsSection");
const itemArray: Array<string> = [];
let itemElement;
let newItem: string;
let itemText: string;
//add new item to shopping list
addButton.onclick=function addItem(){
//add each item to the list
itemElement = document.createElement("li");
newItem = (<HTMLInputElement>document.querySelector("#newItem")).value;
itemText = document.createTextNode(newItem);
itemElement.appendChild(itemText);
itemsSection.appendChild(itemElement);
document.querySelector("#newItem").value="";
//push each item to our array to store in local storage
itemArray.push(newItem);
console.log(itemArray);
itemElement.onclick=function deleteItem(){
var index=itemArray.indexOf(this);
this.parentNode.removeChild(this);
itemArray.splice(index,1);
console.log(itemArray);
}
}
As you can see im using typescript
Your code is failing to find the element in the array:
index=itemArray.indexOf(this);
This is setting index to -1 because the item is not found:
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
When you then call
itemArray.splice(index,1);
You're always removing the last element of the array, because that's how splice works when passed negative numbers:
start
Index at which to start changing the array. If greater than the length of the array, actual starting index will be set to the length of the array. If negative, will begin that many elements from the end.
You need to debug why itemArray.indexOf(this); is not finding the item (and we need to see more code to help you with that) and you should say:
if(index >=0)
itemArray.splice(index,1);
else
console.log("Could not find index"); // or better error handling ;-)
Try changing:
//push each item to our array to store in local storage
itemArray.push(newItem);
to:
//push each item to our array to store in local storage
itemArray.push(itemElement);
If that doesn't work, try adding an attribute to itemElement containing the index of the element in itemArray, so that you can know which element to remove without having to rely on indexof() and DOM objects. Something like this totally untested version of your code:
const addButton =<HTMLButtonElement>document.querySelector("#addButton");
const saveButton = document.querySelector("#saveButton");
const itemsSection = document.querySelector("#itemsSection");
const itemArray: Array<string> = [];
let itemElement;
let newItem: string;
let itemText: string;
//add new item to shopping list
addButton.onclick=function addItem(){
//add each item to the list
itemElement = document.createElement("li");
newItem = (<HTMLInputElement>document.querySelector("#newItem")).value;
itemText = document.createTextNode(newItem);
itemElement.appendChild(itemText);
itemsSection.appendChild(itemElement);
document.querySelector("#newItem").value="";
// ***here** store the index of the element:
itemElement.id = "itemIndex_" + (itemArray.push(newItem) -1);
console.log(itemArray);
itemElement.onclick=function deleteItem(){
// get my index from my ID rather than indexOf:
var index=parseInt(this.id.split('_')[1]);
this.parentNode.removeChild(this);
itemArray.splice(index,1);
console.log(itemArray);
}
}

Categories