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.