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

JavaScript Interactive Web Pages with JavaScript Traversing and Manipulating the DOM with JavaScript Perform: Appending and Removing Elements

What is happening when we bindTaskEvents?

What is happening in this function:

var bindTaskEvents = function(taskListItem, checkBoxEventHandler) {
  console.log("Bind list item events");
  //select taskListItem's children
  var checkBox = taskListItem.querySelector("input[type=checkbox]");
  var editButton = taskListItem.querySelector("button.edit");
  var deleteButton = taskListItem.querySelector("button.delete");


It is called in an instance like this:

//Mark a task as incomplete
var taskIncomplete = function() {
  console.log("Task incomplete...");
  //Append the task list item to the #incomplete-tasks
  var listItem = this.parentNode;
  bindTaskEvents(listItem, taskCompleted);

I get really really confused about this at about minute 7:30 in the video. Where Andrew is explaining

var listItem = this.parentNode

I thought we were appending a child, not a parentNode.

Please help explain! Thank you!

1 Answer

Meagan Waller
Meagan Waller
19,382 Points

Hi Jennelle,

The bindTaskEvents function is the function that we pass our taskListItem to when we loop through every li element in the ul#incomplete-tasks or the ul#completed-tasks.

Basically, what this is doing is for every li it's binding some events to children elements located in that li.

If you take a look at your index.html file you'll see that each li has some elements inside of it,

<li><input type="checkbox"><label>Pay Bills</label><input type="text"><button class="edit">Edit</button><button class="delete">Delete</button></li>

(this an example inside of the ul#incomplete-tasks.)

However, we want actions to be able to happen when the user presses the edit button, or checks the checkbox, for instance. The way we make this happen is by binding our events (the functions we created in the beginning stages, like editTask or deleteTask) to those elements. Otherwise, when we click the delete button, nothing will happen because our delete button hasn't been told to listen for an onclick action from the user.

You'll see inside of the bindTaskEvents function that we're setting editButton.onclick = editTask. When we do this, what we're doing is setting that editButton located in that particular taskListItem to perform the editTask function when that particular button is clicked. That means that when that particular edit button is clicked, and the editTask function is executed (because we are telling it to listen for when the user clicks) it will perform that editTask function in the context of that particular edit button.

Alright, so hopefully that explains the bindTaskEvents function a little more clearly.

The reason that bindTaskEvents is being called in our taskIncomplete function is because we're creating a new list item that didn't exist the first time we called bindTaskEvents. Remember a couple of videos back when we created the for loop that cycled (or iterated) over all our elements inside both the incompleteTasksHolder and completedTasksHolder? Well, now we've appended a new list item (either by the user marking a task as incomplete, or by creating a new task) to that incompleteTasksHolder but since it wasn't part of the incompleteTasksHolder when we initially ran our program (and bound the events to each li that was already inside of the window.document (document)) we need to bind events to the elements located inside of the new tasks li so that it behaves as expected. Without using the bindTaskEvents function on new tasks the user creates, pressing the edit, or delete button, for instance, will do nothing. For each new li that gets created when a user creates a new task we need to tell it's edit button, delete button, checkbox, etc, what to do what the user interacts with those particular elements.

And what we're doing with the var listItem = this.parentNode is a little bit confusing, but I'll try my best to explain :)

When we're inside of the taskIncomplete function it's because it's been triggered on a checkbox. If you'll remember in the bindTaskEvents function we add this line:

checkBox.onchange = checkBoxEventHandler;

(and the checkBoxEventHandler is just a function that we passed in in the second argument), so for the sake of this example:

checkBox.onchange = taskIncomplete;

so this means, when the user changes this check box the taskIncomplete function is being executed. However, when the function gets executed, it's in the scope of the check box, so if we were to put console.log(this) inside of the taskIncomplete function you'd see that this in the scope of that function is the checkBox.

But, what we need is to know the parent of the check box, that's why you see:

var listItem = this.parentNode;

because if we just said:

var listItem = this;

it wouldn't be correct, because this listItem isn't the check box, it should be the li that the check box is located inside of. By calling this.parentNode we are getting access to the parent of the check box (it's sort of like the opposite of the .children method we used inside of our for loop)

Once we have access to the listItem, then we can append it (the entire listItem) to the incompleteTasksHolder.

I hope this was helpful, if there's anything that I skipped over or if you feel lost please let me know!


That totally cleared things up for me!

That was a very thoughtful answer. I wish I could upvote this like 20 more times.

Thank you!