Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

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

Aleks Dahlberg
Aleks Dahlberg
19,103 Points

Problem: List item elements not being created when a list item is created.

On the click event to add a new task, the elements (inputs, label and buttons) are not being created. Note: my HTML and CSS is slightly modified compared to the workspace assets. My javascript is also slightly modified compared to the videos.

Javascript

//Problem: User interaction does not provide desired results.
//solution: add interactivity so the user can manage the todo list.
var taskInput = document.getElementById('todoInput');
var addButton = document.getElementById('addTaskButton');
var incompleteTaskHolder = document.getElementById('incompleteTasks');
var completedTaskHolder = document.getElementById('completedTasks');



/*This function creates the the list items.*/
var createListItem = function(taskString){

    //list item will be the parent of the checkbox, label, text... etc
    var listItem = document.createElement("li");
    listItem.className = "p-t-2";

    //create and modify child elements
    var checkbox = document.createElement("input");
    checkbox.type = "checkbox";

    var label = document.createElement("label");
    label.innerHTML = taskString;

    var editInput = document.createElement("input");
    editInput.type = "text";
    editInput.className = "form-control task-form"; //apply classes

    var deleteButton = document.createElement("button");
    //check if innerText string is "undefined" (firefox)
    if (typeof deleteButton.innerText === "undefined"){
        deleteButton.innerContent = "Delete";
    } else {
        deleteButton.innerText = "Delete";
    }
    deleteButton.className = "btn btn-secondary delete"; //apply classes

    var editButton = document.createElement("button");
    //check if innerText string is "undefined" (firefox)
    if (typeof editButton.innerText === "undefined"){
        editButton.innerContent = "edit"
    } else {
        editButton.innerText = "edit"
    }
    editButton.className = "btn btn-secondary edit"; //apply classes

    //append child elements to listItem parent.
    checkbox.appendChild(listItem);
    label.appendChild(listItem);
    editInput.appendChild(listItem);
    deleteButton.appendChild(listItem);
    editButton.appendChild(listItem);

    console.log("Task created"); //console message
    return listItem; //return the listItem
}



/*This function adds the created list items from createListItem function
to the unordered list html & incompleteTaskHolder on the click event of
addButton */
var addTask = function () {
    //create variable listItem and store the returned created item from createListItem
    var listItem = createListItem(taskInput.value); //use the value of taskInput as the taskString

    //append listItem to incompleteTaskHolder
    incompleteTaskHolder.appendChild(listItem);
    bindTaskEvents(listItem, taskCompleted);
    console.log("Task added!"); //console message
}



//edit existing tasks
var editTask = function (){
    console.log("Task in edit-mode");
}



//delete tasks
var deleteTask = function () {
    //traversing:
    //create a variable to store the li from the listItem's parent
    var listItem = this.parentNode;

    //create a variable to store the ul as listItem's parent
    var ul = listItem.parentNode;

    //remove the child
    ul.removeChild(listItem);

    console.log("task deleted!"); // console message
}



//mark tasks completed
var taskCompleted = function (){
    //append the list item to completedTasks
    var listItem = this.parentNode;

    //add listItem to parent node (completedTaskHolder)
    completedTaskHolder.appendChild(listItem);

    //bind task events to the new list item.
    bindTaskEvents(listItem, taskIncomplete);

    console.log("task completed!"); //console message
}



//mark tasks incomplete
var taskIncomplete = function () {
    //
    var listItem = this.parentNode;

    //add listItem to parent node (incompleteTaskHolder)
    incompleteTaskHolder.appendChild(listItem);

    //bind task events to the new list item.
    bindTaskEvents(listItem, taskCompleted);

    console.log("task incomplete!"); //console message
}



/*This function binds the list item event elements (checkboxes and buttons) to the
appropriate event handers*/
var bindTaskEvents = function (listItem, checkboxEventHandler) {

    //create variables to store each element (get element by type)
    var checkbox = listItem.querySelector("input[type=checkbox]");
    var editButton = listItem.querySelector("button.edit");
    var deleteButton = listItem.querySelector("button.delete");

    //set event handlers
    editButton.onclick = editTask;
    deleteButton.onclick = deleteTask;
    checkbox.onchange = checkboxEventHandler;

    console.log("List item events bound"); //console message
}



//while i is less than then number of items in incompleteTaskHolder (ul) children (li) bind the events to the (ul) children (li) using the bindTaskEvents function
for(var i = 0; i < incompleteTaskHolder.children.length; i++){
    bindTaskEvents(incompleteTaskHolder.children[i], taskCompleted);
    console.log("Tasked added to incompleteTaskHolder"); //console message
}



//while i is less than then number of items in completedTaskHolder (ul) children (li) bind the events to the (ul) children (li) using the bindTaskEvents function
for(var i = 0; i < completedTaskHolder.children.length; i++){
    bindTaskEvents(completedTaskHolder.children[i], taskIncomplete);
    console.log("task added to completedTaskHolder"); //console message
}



//wiring
addButton.onclick = addTask; //onclick run addTask function

HTML

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css">
        <link rel="stylesheet" href="css/master.css" media="screen" title="no title" charset="utf-8">
    </head>
    <body>
        <div class="container p-t-3 p-b-3">
            <div class="row">
                <h4 id='title3'>To do list</h4>

                <!--NEW TASK HTML-->
                <div class="p-t-2">
                    <label class="label-heading">ADD ITEM</label>
                    <ul>
                        <li class="add-task-li">
                            <input class="form-control task-form" id="todoInput">
                            <button  class="btn btn-secondary" type="button" name="button" id="addTaskButton">ADD</button>
                        </li>
                    </ul>
                </div>

                <!--INCOMPLETE TASK HTML-->
                <div class="p-t-2">
                    <label class="label-heading">INCOMEPLETE TASKS</label>
                    <ul id="incompleteTasks">

                        <!--not edit mode-->
                        <li class="p-t-1">
                            <input type="checkbox" class="checkbox-style"/>
                            <label>Test item not edit mode</label>
                            <input type="text"/>
                            <button class="btn btn-secondary edit" type="button" name="button" id="editButton">Edit</button>
                            <button class="btn btn-secondary delete" type="button" name="button" id="deleteButton">Delete</button>
                        </li>

                        <!--edit mode-->
                        <li class="edit-mode p-t-1">
                            <input type="checkbox" class="checkbox-style"/>
                            <label>Test item edit mode</label>
                            <input type="text" class="form-control task-form" value="Test item edit mode"/>
                            <button class="btn btn-secondary edit" type="button" name="button" id="editButton">Edit</button>
                            <button class="btn btn-secondary delete" type="button" name="button" id="deleteButton">Delete</button>
                        </li>
                    </ul>
                </div>

                <!--COMPLETED TASK HTML-->
                <div class="p-t-2">
                    <label class="label-heading">COMPLETED TASKS</label>
                    <ul id="completedTasks">
                    </ul>
                </div>

            </div>
        </div>
        <script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script>
        <script src="js/todoapp.js" charset="utf-8"></script>
    </body>
</html>

2 Answers

Shane Oliver
Shane Oliver
19,950 Points

You have your appendchild set the wrong way around in the createlistitem function

you are saying : checkbox.appendChild(listItem); where it should be : listItem.appendChild(checkbox)