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

Todo App - Undefined error

I've reviewed the videos multiple time and I'm not finding anything.

You create a function, then an element is added "taskListItem". I'm getting an error "Uncaught TypeError: Cannot read property 'query Selector' of undefined."

I can't find where it was ever defined. I think my question is, when was "taskListItem" defined and what is it?

var bindTaskEvents = function(taskListItem, checkBoxEventHandler) {
  console.log("Bind list items events");
  //select taskListItems' 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 delete button
    deleteButton.onclick = deleteTask;

    //bind checkBoxEventHandlerto the checkbox
    checkBox.onchange = checkBoxEventHandler;
}

6 Answers

Dave McFarland
STAFF
Dave McFarland
Treehouse Teacher

Hi Mike Fondario

taskListItem is the parameter in the bindTaskEvents function -- what I mean, is that when you call the bindTaskEvents function you pass a DOM element to the function. For example, the taskCompleted function calls the bindTaskEvents function passing a list item and a callback function:

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

The most likely cause of this Uncaught TypeError: Cannot read property 'querySelector' of undefined error is that your code isn't actually passing in a DOM element to the bindTaskEvents function. The browser is looking for a 'querySelector' property on the object -- taskListItem.querySelector("input[type=checkbox]") for example. That's a method of a DOM element, but because the function was passed something "undefined" there is no querySelector property -- that's why you're getting an error.

The finished script calls the bindTaskEvents function in 5 different places: the addTask function, the taskCompleted function, the taskIncomplete function, and at the bottom of the script inside two for loops you need to look in these to see where the typo is. Or, better yet, because the three functions have a console.log call in them, you should see a message like "Task complete..." in the console just before the error. This message should indicate which function the error is in. If there is no message, then the error is in one of the for loops at the bottom of the script.

Hope that helps.

HUGE HELP! WIth your answer I found the error in 60 seconds. The console was telling me there was an error on line X, but I didn't understand it was because different functions were being passed through it.

Great explanation and great help.

Thanks,

Seems like the taskListItem argument is not being passed in. I'm not sure why as your code looks okay to me. A bug in the workspace maybe?

Liam Hammersley
Liam Hammersley
7,991 Points

Hi Mike,

I had the same problem with my code and I was just wanting to confirm with you what you changed to resolve your issues. Was the error in the for loop?

Hey Liam,

That's correct, if your console is giving 1-2 bind list item events then the error, the problem probably is in your for loop.

Chad Ridings
Chad Ridings
1,002 Points

Okay, somewhat frustrating as I'm spending way too much time trying to figure this out, and obviously others are having the exact same issue. I've watched this video over 5 times and I get exactly the same error as Mike.

My code is verbatim to the tutorial and since this is my first JS app ever I do not have the skills to troubleshoot this issue. I'm working outside the workspace on an actual html/css/js file... so the workspace is not the issue for me.

Uncaught TypeError: Cannot read property 'querySelector' of undefined

bindTaskEvents (anonymous function)

Here is my code...

// Problem: User interaction doesn't provide desired results
// Solution: Add interactivity so that the user can manage daily tasks

var taskInput = document.getElementById("new-task");
var addButton = document.getElementsByTagName("button")[0];
var incompleteTaskHolder = document.getElementById("incomplete-tasks");
var completedTaskHolder = document.getElementById("completed-tasks");



// Add a new task
var addTask = function () {
    console.log("Add task...");
    // When the button is pressed create a new task
    //Create a new list item with the text from "#new-task"
        // input (checkbox)
        // label
        // input (text)
        // button.edit
        // button.delete
        // Each elements, needs to be modified and appended
};


// Edit an existing task
var editTask = function () {
    console.log("Edit task...");
    // When the edit button is pressed
        // If the class of the parent has the class .editMode
            // Switch from .editMode
            // Make the 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...");
    // When the checkbox is checked
        // Append the task list item to the #completed-tasks
};


// Mark a task as incomplete
var taskIncomplete = function () {
    console.log("Task incomplete...");
    // When the checkbox is unchecked
        // Append the task list item to the #incomplete-tasks
};


var bindTaskEvents = function (taskListItem, checkBoxEventHandler) {
    console.log("Bind list items event");
    // Select taskListItem'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 delete button
    deleteButton.onclick = deleteTask;

    // Bind checkBoxEventHandler to the checkbox
    checkBox.onchange = checkBoxEventHandler;
}


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


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


// Cycle over the incompleteTaskHolder ul list items
for(var i = 0; i < incompleteTaskHolder.children.length; i++) {
    // Bind events to list item's children (taskIncomplete)
    bindTaskEvents(completedTaskHolder.children[i], taskCompleted);
}
Chad Ridings
Chad Ridings
1,002 Points

Thanks Mike... I've ran through Dave's instructions above... calling each one from the console addTask(), editTask(), deleteTask(), etc... no error messages. It comes back with the correct console message (ie. "Task incomplete..."), followed by undefined.

I'm not done with the project yet, I just noticed this error message on my console while going through the work on Andrews tutorial... but Andrews did not throw this error message in the tutorial, and my code is exactly his... so just a bit confused.

Markdown isn't displaying my code correctly. 3rd attempt. Edit: as usual I'm an idiot, user error.

Chad,

My error wasn't in the line the my text editor was telling me. It was in a variable outside of the function that the function was using. Hope this helps.

//User Interaction doesn't provide desired results
//Solution: Add interactivity so user can manage daily task

var taskInput = document.getElementById("new-task"); //new-task
var addButton = document.getElementsByTagName("button")[0]; //first button
var incompleteTasksHolder = document.getElementById("incomplete-tasks"); //incomplete-task
var completedTasksHolder = document.getElementById("completed-tasks"); //completed-task

 //New Task List Item
  var createNewTaskElement = function(taskString) {
    //Create List Item
    var listItem = document.createElement("li");
    //Input (checkboxes)
    var checkBox = document.createElement("input"); //checkbox
    //label
    var label = document.createElement("label");
    //Input (text)
    var editInput = document.createElement("input");
    //Button.edit
    var editButton = document.createElement("button");
    //Button.delete
    var deleteButton = document.createElement("button");

    //Each Element need 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 new list item from the #new-task
  var listItem = createNewTaskElement(taskInput.value);

  //Appen listItem to IncompletTasksHolder
  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 the class of parent is .editMode

  if(containsClass){
    //Switch from .editMode
    //label text becomes the input value
    label.innerText = editInput.value;
} else {
    //Switch to .editMode
    //Input value becomes the label's text
  editInput.value = label.innerText;
}
  //Toggle edit mode on the listItem
  listItem.classList.toggle("editMode");
}

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

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

//Mark a task as complete
var taskCompleted = function() {
  console.log("Complete Task...");
    //Append the task li to the #complete-task
  var listItem = this.parentNode;
  completedTasksHolder.appendChild(listItem);
  bindTaskEvents(listItem,taskIncomplete);
}

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

var bindTaskEvents = function(taskListItem, checkBoxEventHandler) {
  console.log("Bind list items events");
  //select taskListItems 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 delete button
    deleteButton.onclick = deleteTask;

    //bind checkBoxEventHandlerto the checkbox
    checkBox.onchange = checkBoxEventHandler;
}

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

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


//cycle over incompleteTasksHolder ul list items
for(var i = 0; i < incompleteTasksHolder.children.length; i++){
    //bind events to list iitems 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 items children(taskIncomplete)
    bindTaskEvents(completedTasksHolder.children[i], taskIncomplete);
}
Chad Ridings
Chad Ridings
1,002 Points

Thanks for sharing Mike. I was able to compare your code to mine and I noticed where I had a typo. I've fixed it and it is working like a champ now. It was a typo in my for loop at the end of the page. The loops were conflicting with each other. Thanks mate!