Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial

damien marez
6,085 PointsInput Checked / Unchecked
Hi everyone,
I have a problem with my JavaScript. I try to do the JavaScript TODO web app in my way and I'm stuck on something. When the user writes the task to do and click on the button ADD, it creates a LI with an input (checkbox), a text, and two buttons and put it all in the part => Incomplete Task. I would find a way to trigger an event when the user checks the checkbox (when the user checks the checkbox, full LI appears in another location (CompleteTask).
I'm sorry for my English and I hope I'm clear enough. Thanks in advance
// My JavaScript
/********* Variables *********/
/********* Variables *********/
var buttonAddNewTask = document.getElementById('buttonAdd');
var newLi;
var newCheckBox;
/********* Functions *********/
/********* Functions *********/
var newTask = function () {
// Add the value of the input after the checkbox
var retrieveInputNewTask = document.getElementById('addTask').value;
if (retrieveInputNewTask === "") {
alert('Please enter a task');
} else {
// Create a LI
newLi = document.createElement('li');
newLi.classList.add('marginLi');
// Add checkbox input in the LI
newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.checked;
newLi.appendChild(newCheckBox);
var textAfterCheckBox = document.createTextNode(retrieveInputNewTask);
newLi.appendChild(textAfterCheckBox);
//Add new buttons after the input (edit and delete)
var newButtonEdit = document.createElement('button');
newButtonEdit.classList.add('buttonTask','buttonEdit');
var textButtonEdit = document.createTextNode('Edit');
newButtonEdit.appendChild(textButtonEdit);
newLi.appendChild(newButtonEdit);
var newButtonDelete = document.createElement('button');
newButtonDelete.classList.add('buttonTask', 'buttonDelete');
var textButtonDelete = document.createTextNode('Delete');
newButtonDelete.appendChild(textButtonDelete);
newLi.appendChild(newButtonDelete);
// add all to the end of the UL
var positionUl = document.querySelector('ul');
positionUl.appendChild(newLi);
//Event
newButtonDelete.addEventListener('click', deleteTask);
}
};
// Remove the task when the user click on the delete button
var deleteTask = function(){
//when user click on delete button, it removes the Li
this.parentNode.remove(this.parentNode);
}
/********* Global Event *********/
/********* Global Event *********/
buttonAddNewTask.onclick = newTask;
My HTML
<!DOCTYPE html>
<html lang="en">
<head>
<title>TODO list</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/main.css">
</head>
<body>
<div id="mainTitleDiv" class="container">
<h1>MY TASK</h1>
</div>
<div id="addTaskDiv">
<h3 class="divTitle">Add a Task</h3>
<p><input type="text" id="addTask" placeholder="Write your task here"></p>
<p><button type="button" id="buttonAdd">Add</button></p>
</div>
<hr>
<div id="incompleteTask" class="container">
<h3 class="divTitle">To Do</h3>
<ul class="noBullets noPadding"></ul>
</div>
<hr>
<div id="completeTask" class="container">
<h3 class="divTitle">Done</h3>
<ul class="noBullets noPadding">
</ul>
</div>
<script src="js/main.js"></script>
</body>
</html>
3 Answers

miikis
44,957 PointsGlad it worked out for you, Damien. The call method is one that all functions have. Basically, you know how inside of the function deleteTask you were using the keyword this to access the element that was clicked? Well, that only worked because you were directly passing deleteTask as an event listener argument to addEventListener — like this:
newButtonDelete.addEventListener('click', deleteTask);
The moment you decide to call deleteTask as a regular function — that is, outside of addEventListener —, the JS interpreter has no idea what you mean by this (actually, though, it just assumes this is referring to the global object — window — which won't work). This breaks your intended functionality for deleteTask.
To fix what this means at any given time, JS makes available to every function a total of 3 methods: call, apply and bind. All three methods perform the same function but in slightly different ways. All three methods accept, as their first argument, whatever you want this to be. In your case, we want this to be the clicked-on element so we just passed this (note that this in this case referred to the clicked element and not the window object because we are inside of the listener passed to addEventListener).
After you pass in the object that you want this to reference, call then accepts any arguments that you want to pass to the function. In this case, deleteTask isn't doing anything with the event argument so we didn't have to pass it in ... but I did anyway for shits and giggles.
Similarly, after you pass in what you want this to be for apply, you can pass in any arguments you need. The difference is, though, that apply wants all of your arguments — besides the first one, which should be what you want this to mean, remember? — to be in an array. So, apply will only ever take two arguments: what you want this to be and an array of arguments to pass in.
Likewise, after you pass in what you want this to be for bind, you can also pass in any arguments you need. The difference here is that bind only takes a function as a subsequent argument. This is actually what addEventListener is doing behind the scenes to make it so that you can use this in your event-listeners and have this refer to the target element.
Hope that made sense ;)

miikis
44,957 PointsHey Damien,
One way to do what you're attempting is to listen for the checkbox's click event. You can put this event listener right after your deleteTask listener. Inside of the listener, you can cache the current list-item, then remove the current list-item from the DOM (using your deleteTask function) and then append the current list-item to the completeTask div's unordered-list — like this:
newCheckBox.addEventListener('click', function(event) {
var $completedList = document.querySelector('#completeTask ul')
var $li = this.parentNode
deleteTask.call(this, event);
$completedList.appendChild($li);
})
Let me know if you have any questions :)

damien marez
6,085 PointsThanks a lot Mikis Woodwinter ! It works very well
I understand your code except one line : "deleteTask.call(this, event);
You call the function DeleteTask with : deleteTask.call(); But I don't understand : (this, event); Is it the syntax to say : deleteTask.call(deleteTask, event) ? but what is event ?
I am still not comfortable with the functions.
Thanks in advance
Damien
damien marez
6,085 Pointsdamien marez
6,085 PointsThanks, it's very useful !