简体   繁体   中英

Using splice is removing wrong value from array

I have built a to-do list app in Javascript as all learners will at some point, and I am attempting to use local storage to store the values when the app is closed or refreshed. I'm storing them in these empty arrays:

var data = (localStorage.getItem('todolist')) ? 
JSON.parse(localStorage.getItem('todolist')):{
    todo: [],
    completed: []
};

To do this, whenever an element is added to the list, it goes onto the to-do list and it's array, and when completed, it should be removed from the to-do array and added to the completed one. I've done this using an if statement:

if (id === 'todo') {
    data.todo.splice(data.todo.indexOf(value), 1);
    data.completed.push(value);
  } else {
    data.completed.splice(data.completed.indexOf(value), 1);
    data.todo.push(value);
  }

However, I'm not sure why, the values stored in the array seem to be getting moved in the wrong order eg if values 'a','b','c' are in the to-do array, moving over the 'a' list item from to-do to completed, will result in the the completed array gaining 'a' but the to-do array then removes 'c' instead, leaving 'a' duplicated in storage.

I've console.log(indexOf(value)) in the if statement which is resulting in -1, which I cannot understand why because the array does contain the number and it is created and filled before this point. Any help to point me towards where I'm going wrong would be massively appreciated. Here is my code:

var data = (localStorage.getItem('todolist')) ? 
JSON.parse(localStorage.getItem('todolist')):{
    todo: [],
    completed: []
};

renderTodoList();


//User clicked on add, adding any text in input field to to-do field.
document.getElementById('add').addEventListener('click', function(){
var value = document.getElementById('item').value;
if (value){
    addItem(value);
};
});

document.getElementById('item').addEventListener('keydown', function (e){
var value = this.value;
if (e.code === 'Enter' && value){
    addItem(value);
}
});

function addItem(value) {
addItemToDOM(value);
document.getElementById('item').value = '';

data.todo.push(value);
dataObjectedUpdated();
}

//Render list from memory.
function renderTodoList() {
if (!data.todo.length && !data.completed.length) return;

for (var i = 0; i <data.todo.length; i++){
    var value = data.todo[i];
    addItemToDOM(value);
}

for (var j = 0; j <data.completed.length; j++) {
    var value = data.completed[j];
    addItemToDOM(value, true);
}
}

function dataObjectedUpdated() {
localStorage.setItem('todolist', JSON.stringify(data));
console.log(data);
}

//Delete's item from list.
function removeItem() {
var item = this.parentNode.parentNode;
var parent = item.parentNode;
var id = parent.id;
var value = item.innerText;

if (id === 'todo'){
    data.todo.splice(data.todo.indexOf(value), 1);
} else {
    data.completed.splice(data.completed.indexOf(value), 1);
}
console.log(value);
dataObjectedUpdated();

parent.removeChild(item);
}

//When item is completed or uncompleted - moving between lists.
function completeItem() {
var item = this.parentNode.parentNode;
var parent = item.parentNode;  
var id = parent.id;
var value = item.innerText;


if (id === 'todo') {
    data.todo.splice(data.todo.indexOf(value), 1);
    data.completed.push(value);
  } else {
    data.completed.splice(data.completed.indexOf(value), 1);
    data.todo.push(value);
  }
dataObjectedUpdated();


//Check if item should be added to todo or completed list
var target = (id === 'todo') ? document.getElementById('completed'): document.getElementById('todo');

parent.removeChild(item);
target.insertBefore(item, target.childNodes[0]);
}

//Add item to DOM list
function addItemToDOM(text, completed){

var list = (completed) ? document.getElementById('completed') : document.getElementById('todo');

var item = document.createElement('li');
item.innerText = text;

var buttons = document.createElement('div');
buttons.classList.add('buttons');

var remove = document.createElement('button');
remove.classList.add('remove');
remove.innerHTML = removeSVG;

//Add click event for removing an item
remove.addEventListener('click', removeItem);


var complete = document.createElement('button');
complete.classList.add('complete');
complete.innerHTML = completeSVG;

//Add click event for completing an item
complete.addEventListener('click', completeItem);

buttons.appendChild(remove);
buttons.appendChild(complete);
item.appendChild(buttons);

list.insertBefore(item, list.childNodes[0]);
}

And contained in my body HTML:

<div class="container">
<!-- Incomplete tasks --->
<ul class="todo" id="todo"></ul>

<!--Completed tasks-->
<ul class="todo" id="completed"></ul>
</div>

Thank you in advance!

Change the addToDom function to keep your text within a specified element like span . Also when your're trying to get the innerText , you should get it from this span .

This is the changes of your addToDom function:

var item = document.createElement('li'); var span = document.createElement('span'); span.innerText = text; item.append(span);

In your completeItem function, you should change the value variable to this:

var value = item.getElementsByTagName('span')[0].innerText;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM