im building a to-do list but cant figure out how to keep my array values that have line-through decoration. the moment render method is called, the array is built from the start. means that if i delete an li, all other li that have been marked by the checkbox with a line-through, losing the decoration. what can i do to keep the line-through ? i tried so far in the markTask method to replace the original value with the value that have line-through on it but it didn’t work. basically what im trying to accomplish is by inserting the value with line-through, to be able to check if this value have the line-through style and after the render to be able to keep the checked checkboxes as checked.
my code so far:
class Todo { constructor() { this.input = document.getElementById("input"); this.ul = document.getElementById("ul"); this.form = document.getElementById("form"); this.tasks = []; this.registerEvent(); } registerEvent() { this.form.addEventListener("submit", (event) => { event.preventDefault(); this.createTask(this.input.value); this.form.reset(); }); } createTask(task) { if (task.trim().length === 0) { return; } this.tasks.push(task); this.render(); } deleteTask(task) { const myTask = task.target; const parent = myTask.parentNode; const taskToRemove = parent.childNodes[1].textContent; const index = this.tasks.indexOf(taskToRemove); this.tasks.splice(index, 1); this.render(); } markTask(task) { const myTask = task.target; const parent = myTask.parentNode; if (myTask.checked) { parent.style.textDecoration = "line-through"; } else { parent.style.textDecoration = "none"; } } render() { this.ul.innerHTML = ""; this.tasks.forEach((task) => { const li = document.createElement("li"); const cb = document.createElement("input"); cb.type = "checkbox"; cb.addEventListener("click", (e) => { this.markTask(e); }); li.appendChild(cb); li.append(document.createTextNode(task)); const btn = document.createElement("button"); li.appendChild(btn); btn.textContent = "Delete"; btn.classList.add("remove"); btn.addEventListener("click", (e) => { this.deleteTask(e); }); this.ul.appendChild(li); }); } } new Todo();
<form id="form"> <input id="input" /> <button id="add">Add</button> </form> <ul id="ul"> </ul>
Advertisement
Answer
it’s because you’re not tracking which tasks are done and you’re just pushing strings. for your createTask
method you need to push an object with a done property to indicate which tasks have been done like so
createTask(task) { if (task.trim().length === 0) { return; } this.tasks.push({title: task, done: false}); this.render(); }
update your render to account for tasks already done
render() { this.ul.innerHTML = ""; this.tasks.forEach((task) => { const li = document.createElement("li"); const cb = document.createElement("input"); cb.type = "checkbox"; cb.addEventListener("click", (e) => { this.markTask(e); }); li.appendChild(cb); li.append(document.createTextNode(task.title)); const btn = document.createElement("button"); li.appendChild(btn); btn.textContent = "Delete"; btn.classList.add("remove"); btn.addEventListener("click", (e) => { this.deleteTask(e); }); this.ul.appendChild(li); if (task.done) { cb.checked = true; li.style.textDecoration = "line-through"; } else { cb.checked = false; li.style.textDecoration = "none"; } }); }
in your constructor update your tasks variable to see this in effect
constructor() { this.input = document.getElementById("input"); this.ul = document.getElementById("ul"); this.form = document.getElementById("form"); this.tasks = [{title: 'mill', done: true}, {title: 'jus', done: false}]; this.registerEvent(); }
hope you get the general idea. I won’t do the entire implementation on markTask
as this should be enough to give you a view of what the solution should be. good luck.