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

this.parentNode

First what is the value of listItem in the taskIncomplete function and the taskCompleted function?

Second how does this.parentNode give it that value? I guess I don't understand how this.parentNode works.

// Problem: User interaction does not provide desired results.
// Solution: Add interactivity so the user can manage daily tasks.

var taskInput = document.getElementById("new-task");
var addButton = document.getElementById("addButton");
var incompleteTasksHolder = document.getElementById("incomplete-tasks");
var completedTasksHolder = document.getElementById("completed-tasks");

// New task list item
var createNewTaskElement = function(taskString) {
    // Create list item
    var listItem = document.createElement("li");

    // input (checkbox)
    var checkBox = document.createElement("input"); // checkbox

    // label
    var label = document.createElement("label");

    // input (text)
    var editInput = document.createElement("input"); // edit input text

    // button.edit
    var editButton = document.createElement("button") // button.edit

    // button.delete
    var deleteButton = document.createElement("button"); // button.delete

    // each elements need to be modified 


    // each element needs appended
    listItem.appendChild(checkBox);
    listItem.appendChild(label);
    listItem.appendChild(editInput);
    listItem.appendChild(editButton);
    listItem.appendChild(deleteButton);

    return listItem;
}

// Add a new task
var addTask = function() {
    console.log("add task");
    // Create a new list item with the text from #new-task:
    var listItem = createNewTaskElement("Some new task");

    // Append listItem to incompleteTaskHolder
    incompleteTasksHolder.appendChild(listItem);
    bindTaskEvents(listItem, taskCompleted);
}

// Edit and existing task
var editTask = function() {
    console.log("edit task");
    // When the edit button is pressed
        // if the class of the parent is .editMode
            // switch from editMode
            // label text become the input's value
        // else
            // switch to editMode
            // input value becomes the label's text
        // toggle .editMode on the parent
}

// Delete an existing task
var deleteTask = function() {
    console.log("delete task");
    // When the delete button is pressed
        // remove the parent list item from the ul
}

// Mark a task as complete
var taskCompleted = function() {
    console.log("task complete");
    // append the task list item to the completed-tasks
    var listItem = this.parentNode;
    completedTasksHolder.appendChild(listItem);
    bindTaskEvents(listItem, taskIncomplete);
}

// Mark a task as incomplete
var taskIncomplete = function() {
    console.log("task incomplete");
    // append to the incomplete-tasks
    var listItem = this.parentNode;
    incompleteTasksHolder.appendChild(listItem);
    bindTaskEvents(listItem, taskCompleted);
}

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

    // bind editTask to edit button
    editButton.onclick = editTask;

    // bind deleteTask to the deleteButton
    deleteButton.onclick = deleteTask;

    // bind checkBoxEventHandler to checkbox
    checkBox.onchange = checkBoxEventHandler;

}

// Set the click handler to the addTask function
addButton.onclick = addTask;

// cycle over incompleteTaskHolder ul list items
for (var i = 0; i < incompleteTasksHolder.children.length; i++) {
    // bind events to list item's children (taskCompleted)
    bindTaskEvents(incompleteTasksHolder.children[i], taskCompleted);
}

//cycle over completeTaskHolder ul list items
for (var i = 0; i < completedTasksHolder.children.length; i++) {
    // bind events to list item's children (taskCompleted)
    bindTaskEvents(completedTasksHolder.children[i], taskIncomplete);
}

1 Answer

Sean T. Unwin
Sean T. Unwin
28,690 Points

First what is the value of listItem in the taskIncomplete function and the taskCompleted function?

This is a <li> inside <ul id="incomplete-tasks"> or <ul id="completed-tasks"> of index.html that has had it's checkbox clicked.

Second how does this.parentNode give it that value? I guess I don't understand how this.parentNode works.

When either of these functions is called it will be a checkbox that is calling it, so the current node is that checkbox. That checkbox is inside of a list item (<li>). That list item is the parentNode.

Each tag in an HTML document is a DOM node, so the parentNode is the parent of the current node. In other words the tag that the currently selected tag is encased in.

I hope that helps to clarify a little. :)

Does javascript need to know it is the checkbox calling it and if it does, where in the code are we using javascript to specify it is a checkbox calling either function?

Sean T. Unwin
Sean T. Unwin
28,690 Points

This is defined in the function bindTaskEvents with

// bind checkBoxEventHandler to checkbox
    checkBox.onchange = checkBoxEventHandler;

Where checkBoxEventHandler is the second argument of the function. This value will be either TasksCompleted or IncompleteTasks function.

Looking at the taskCompleted function, wouldn't the listItem variable be looking for the value before the bindTaskEvents function is executed?

Sean T. Unwin
Sean T. Unwin
28,690 Points

taskCompleted is already bound to the onchange event of all the checkboxes in the <li>'s of the <ul id="incompleted-tasks">, so JavaScript already knows that the checkbox is the selected node. As a result the listItem variable is defined with the parent of the checkbox, which is the <li> that the checkbox is in.

When bindTaskEvents is called at the end of taskCompleted it is re-defining the binding of the onchange event to the checkbox to point to the opposite -- from taskCompleted to IncompleteTask.

The purpose of this, eventually, will be to move the <li> from <ul id="incompleted-tasks"> to <ul id="completed-tasks"> and when that move is made the checkbox needs to be set to enable moving the <li> back to <ul id="incompleted-tasks">.

So the global variables and the two for loops are the only code that's ran when the page loads, everything else is ran based off of some kind of event?

The two for loops bind taskCompleted and taskIncompleted to the checkboxes?

Sean T. Unwin
Sean T. Unwin
28,690 Points

So the global variables and the two for loops are the only code that's ran when the page loads, everything else is ran based off of some kind of event?

Correct

The two for loops bind taskCompleted and taskIncompleted to the checkboxes?

Correct, as well as setting which function is called when each of the buttons is clicked, as defined in bindTaskEvents.

Ah, thank you very much! This seems to make more sense now.

Thanks for taking the time to respond!