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

Keith Corona
Keith Corona
9,553 Points

Interactive webpages with JS: error code in JS Console

Hello All,

I have completed the interactive webpages w/JS course, but I am having an issue with my code. When I open the JS console, I immediately get an Uncaught TypeError: Cannot read property "querySelector" of undefined - bindTaskEvent @app.js:118 and (anonymous function) @app.js:149 .

I don't know what the errors are.

JS

//User interaction doesn't provide desired results

//Solution: add interactivity so the user can manage daily tasks

var taskInput = document.getElementById("new-task"); //new-task
var addButton = document.getElementsByTagName("button")[0]; //first button
var incompleteTasksHolder = document.getElementById("incomplete-tasks"); //incomplete-tasks
var completedTasksHolder = document.getElementById("completed-tasks"); //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("label"); //text
  //button.edit
  var editButton = document.createElement("button");
  //button.delete
  var deleteButton = document.createElement("button");

  //Each element needs modifying 

  checkBox.type = "checkbox";
  editInput.type = "text";

  editButton.innerText = "Edit";
  editButton.className = "edit";
  deleteButton.innerText = "Delete";
  deleteButton.className = "delete";

  label.innerText = taskString;

  //Each element needs appending
  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 list item with the text from #new-task:
  var listItem = createNewTaskElement(taskInput.value);

  //append listitem to incompletetaskholder
  incompleteTasksHolder.appendChild(listItem);
  bindTaskEvents(listItem, taskCompleted);

  taskInput.value = "";
  }

//Edit an existing task
var editTask = function() {
  console.log("Edit task..");
  var listItem = this.parentNode;

  var editInput = listItem.querySelector("input[type=text]");
  var label = listItem.querySelector("label");

  var containsClass = listItem.classList.contains("editMode");
    //If class of parent is .editMode
  if(containsClass) {
      //Switch from editMode
      //label text become input's value
    label.innerText = editInput.value;
  } else {
      //Switch to .editMode
      //input value becomes the label's text
    editInput.value = label.innerText;
  }
    //toggle .editMode on the parent
  listItem.classList.toggle("editMode");
}

//Delete an existing task
var deleteTask = function() {
  console.log("Delete task..");
  var listItem = this.parentNode;
  var ul = listItem.parentNode;

  //Remove parent list item from the ul
  ul.removeChild(listItem);
}

//Mark a task as complete
var taskCompleted = function() {
  console.log("Task complete..");
  //When checkbox checked
    //Append the task li 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..");
  //When checkbox unchecked
    //Append the task li to #incomplete-tasks
  var listItem = this.parentNode
  incompleteTasksHolder.appendChild(listItem);
  bindTaskEvents(listItem, taskCompleted);
}


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");


    //bind the editTask to edit button
    editButton.onclick = editTask;
    //bind deleteTask to the delete button
    deleteButton.onclick = deleteTask;
    //bind checkBoxEventHandler to checkbox
    checkBox.onchange = checkBoxEventHandler;
}

var ajaxRequest = function() {
  console.log("Ajax request");
}

//Set click handler to the addTask function
addButton.addEventListener("click", addTask);
addButton.addEventListener("click", ajaxRequest)


//Cycle over incompleteTasksHolder ul 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 completedTasksHolder ul items
for (var i = 0; i < incompleteTasksHolder.children.length; i++) {
    //bind events to list item's children (taskIncomplete)
  bindTaskEvents(completedTasksHolder.children[i], taskIncomplete);
}

and HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Todo App</title>
    <link href='http://fonts.googleapis.com/css?family=Lato:300,400,700' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8">    
  </head>
  <body>
    <div class="container">
      <p>
        <label for="new-task">Add Item</label><input id="new-task" type="text"><button>Add</button>
      </p>

      <h3>Todo</h3>
      <ul id="incomplete-tasks">
        <li><input type="checkbox"><label>Pay Bills</label><input type="text"><button class="edit">Edit</button><button class="delete">Delete</button></li>
        <li class="editMode"><input type="checkbox"><label>Go Shopping</label><input type="text" value="Go Shopping"><button class="edit">Edit</button><button class="delete">Delete</button></li>

      </ul>

      <h3>Completed</h3>
      <ul id="completed-tasks">
        <li><input type="checkbox" checked><label>See the Doctor</label><input type="text"><button class="edit">Edit</button><button class="delete">Delete</button></li>
      </ul>
    </div>

    <script type="text/javascript" src="js/app.js"></script>

  </body>
</html>

2 Answers

Steven Parker
Steven Parker
229,732 Points

Using a fork of your workspace, I still did not see the error you mention in the console just from opening it.

However, I did notice a couple of issues:

  • on line 20, you create a "label" element, but the comment on line 19 suggests it should be "input" instead
  • on line 147, your iteration limit is based on incompleteTasksHolder but you are binding completedTasksHolder

That second issue certainly could be the cause of the error you mentioned, after performing some operations on the page.

Keith Corona
Keith Corona
9,553 Points

Thank you, Steven. I am not sure if just my version of Chrome was showing those errors or what, but now everything is ok. I also made the changes you suggested and no errors appeared.

Steven Parker
Steven Parker
229,732 Points

I didn't see any errors. It made me wonder if something that wasn't included (like the CSS) might make a difference.

If you are using workspaces, you can make a snapshot of your workspace to share everything at once.

Keith Corona
Keith Corona
9,553 Points

Hi Steven,

Here is a snapshot. https://w.trhou.se/lpe3d4kodd

I didn't mess with the css as it was not needed for this project, but perhaps I clicked on it at one time or another and typed something in. I couldn't catch anything. Thank you