I have a to-do list which I want to be able to cross out tasks as they're completed, as well as delete them by clicking their corresponding "X" button.
I use global variable row which is added to different elements' ID. This is how I differentiate them from other task entries.
This works fine when deleting a task, but not when the checkbox is checked/unchecked. I want to toggle the add-strikethrough CSS class whenever a task's checkbox is clicked.
Relevant HTML:
<body>
<h1>To-Do-List</h1>
<form action="" onsubmit="createElements();return false" id="todo" autocomplete=off>
<input type="text" maxlength="25" id="enter-task" placeholder="Enter a Task">
<button type="button" id="submit-task" onClick="createElements()"><span> </span></button>
</form>
<h4 id="task-header">current tasks</h4>
<form id="container">
<!--This is where the addTask elements go-->
</form>
<script src="script.js"></script>
</body>
Relevant CSS:
.add-strikethrough{
text-decoration: line-through;
text-decoration-color: black;
}
Javascript:
var row = 0;
function createElements(){
//create Checkbox
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("id", "entryCheckbox");
checkbox.setAttribute("value", "unchecked");
checkbox.setAttribute("onClick", "strikeTask(" row ");")
//create label using value from input box
var label = document.createElement("label");
label.setAttribute("id", "entryLabel" row);
label = document.getElementById("enter-task").value;
//create deleteTask img
var deleteTask = document.createElement("img");
deleteTask.src = "images/x.svg";
deleteTask.setAttribute("id", "delete-task");
deleteTask.setAttribute("onClick", "deleteRow(" row ");")
addTask(checkbox, label, deleteTask);
}
//This function appends the elements
function addTask(box, label, x){
const tasks = document.getElementById("container");
const newTask = document.createElement('div');
newTask.classList.add('task-entries');
const header = document.getElementById('task-header');
//Makes sure input field is not empty
if(label !== ""){
//Show task container and header
if(tasks.classList.contains("hide")){
tasks.classList.replace('hide', 'task-container');
header.classList.replace('hide', 'show-header')
};
//Append newTask to tasks container
tasks.appendChild(newTask);
newTask.setAttribute("id", "contentDiv" row);
newTask.appendChild(box);
newTask.appendChild(document.createTextNode(label));
newTask.appendChild(x);
row ;
//Resets input field after task is added
document.getElementById("enter-task").value = null;
}
}
function deleteRow(ID){
document.getElementById('contentDiv' ID).remove();
tasks = document.getElementById('container');
header = document.getElementById('task-header');
//Hide header and task container if no tasks exist
if(tasks.children.length == 0){
tasks.classList.replace('task-container', 'hide');
header.classList.replace('show-header', 'hide');
}
}
function strikeTask(ID){
const x = document.getElementById('entryLabel' ID);
x.classList.toggle('add-strikethrough');
}
The strikeTask function is where my problem is; I can't figure out how to apply the class to the label when I click the corresponding checkbox
I appreciate any help!
CodePudding user response:
One way to check what is wrong is to inspect the element created. If you do that you will notice that you don't have a label within a div, only text within a div, because you create a text node with the value of the label, as seen here:
You cannot apply a class to a text node. So you have to create the label element, add text to the label element, then append it.
Here is updated Javascript that will do that:
var row = 0;
function createElements(){
//create Checkbox
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("id", "entryCheckbox");
checkbox.setAttribute("value", "unchecked");
checkbox.setAttribute("onClick", "strikeTask(" row ");")
//create label using value from input box
var label = document.createElement("label");
label.setAttribute("id", "entryLabel" row);
label.textContent = document.getElementById("enter-task").value;
//create deleteTask img
var deleteTask = document.createElement("img");
deleteTask.src = "images/x.svg";
deleteTask.setAttribute("id", "delete-task");
deleteTask.setAttribute("onClick", "deleteRow(" row ");")
addTask(checkbox, label, deleteTask);
}
//This function appends the elements
function addTask(box, label, x){
const tasks = document.getElementById("container");
const newTask = document.createElement('div');
newTask.classList.add('task-entries');
const header = document.getElementById('task-header');
//Makes sure input field is not empty
if(label !== ""){
//Show task container and header
if(tasks.classList.contains("hide")){
tasks.classList.replace('hide', 'task-container');
header.classList.replace('hide', 'show-header')
};
//Append newTask to tasks container
tasks.appendChild(newTask);
newTask.setAttribute("id", "contentDiv" row);
newTask.appendChild(box);
newTask.appendChild(label);
newTask.appendChild(x);
row ;
//Resets input field after task is added
document.getElementById("enter-task").value = null;
}
}
function deleteRow(ID){
document.getElementById('contentDiv' ID).remove();
tasks = document.getElementById('container');
header = document.getElementById('task-header');
//Hide header and task container if no tasks exist
if(tasks.children.length == 0){
tasks.classList.replace('task-container', 'hide');
header.classList.replace('show-header', 'hide');
}
}
function strikeTask(ID){
const x = document.getElementById('entryLabel' ID);
x.classList.toggle('add-strikethrough');
}
What I've changed: label = document.getElementById("enter-task").value;
to label.textContent = document.getElementById("enter-task").value;
inside createElements()
& newTask.appendChild(document.createTextNode(label));
to newTask.appendChild(label);
inside addTask(...)
.
The label is created as you were creating it; its text content is set to the value of the enter-task input; the element is appended.
What you were doing was create a label element and giving it an id, but on the following line (label = document.getElementById("enter-task").value;
) changing the value of the label variable to a text, then adding that text as a text node (newTask.appendChild(document.createTextNode(label));
).