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

Creating a To Do list with jQuery

Hi there,

I just finished the "Making Interactive Web Pages with JavaScript" videos. In those videos, Andrew Chalkley uses JavaScript to create a to-do list. (See videos here: https://teamtreehouse.com/library/interactive-web-pages-with-javascript)

I am currently trying to build that same webpage using jQuery. Has anybody at Treehouse already worked this out? I am running into trouble with my code, and it would be great to reference another student's work in order to figure out where I'm going wrong.

Thanks in advance for any help!

Rose

p.s. The trouble I am having currently is deleting items on the to-do list. I have made it possible for any pre-existing item to be deleted, but I can't delete items that I add to the page. Here's the JS code so far:

var $newTask = $("#new-task");
var $toDoList = $("#incomplete-tasks");
var $completedList = $("#completed-tasks");
var $addButton = $("#add-button");
var $deleteButton = $(".delete-button");
var $editButton = $(".edit-button");
var $checkbox = $(".checkbox");
var $label = $("label");
var $editInput = $("input[type=text]");

//generate new list item
var makeNewListItem = function(taskToAdd) {

  var $newListItem = $("<li></li>");
  var $newCheckbox = $("<input type='checkbox' class='checkbox'>");
  var $newLabel = $("<label></label>");
  var $newEditInput = $("<input type='text' class='edit-text'>");
  var $newEditButton = $("<button class='edit-button'>Edit</button>");
  var $newDeleteButton = $("<button class='delete-button'>Delete</button>");

  $newListItem.append($newCheckbox)
  .append($newLabel.html(taskToAdd))
  .append($newEditInput)
  .append($newEditButton)
  .append($newDeleteButton);

  return $newListItem;
}

//add new list item to To-Do list when add-button is clicked
$addButton.on( "click", function(){
  var listItem = makeNewListItem($newTask.val());
  $toDoList.append(listItem);
  $newTask.val("");
})

//delete list item from list when delete-button is clicked
$deleteButton.on( "click", function(){
  $(this).parent().remove();  
});

and here's my 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 id="add-button">Add</button>
      </p>

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

      </ul>

      <h3>Completed</h3>
      <ul id="completed-tasks">
        <li><input type="checkbox" class="checkbox"checked><label>See the Doctor</label><input type="text" class = 'edit-text'><button class="edit-button">Edit</button><button class="delete-button">Delete</button></li>
      </ul>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>

I have a feeling the solution might be about binding events . . . there was a lot of code with the original JS solution that involved that. I am still trying to wrap my head around the intricacies of what Andrew was talking about. Maybe once I figure that out, I'll be able to figure out my problem.....

1 Answer

David Bath
David Bath
25,940 Points

Hi Rose, it's me again! If I'm not mistaken, the problem has to do with the fact that the delete button is a dynamically created element within the new task. So the $deleteButton variable does not actually contain that element at the time you are attaching the click functionality. One way to do this would be to modify that line slightly like this so that the event gets delegated from the parent list element:

$toDoList.on( "click", ".delete-button", function(){
  $(this).parent().remove();  
});
$completedList.on( "click", ".delete-button", function(){
  $(this).parent().remove();  
});

Oh man, that's it! Ya saved the day again. Thank you!!!

(I'd been trying to figure that out for a few hours. Now I can finally tackle the other stuff... :) !)

David: Thanks once again! I was able to finish writing the program in jQuery. Don't think I could have done that without your tip :)

All Treehouse Peeps: if you're having trouble understanding just what Andrew is doing in the "Making Interactive Web Pages with JavaScript", you might want to finish watching all the videos and then try writing the To-Do list program using jQuery. This helped me understand more what's going on. If you'd like to see the code I wrote as a reference, check out what follows. It works (fingers crossed), although I am sure there are more ways to trim it up, especially with the makeNewListItem function. But anyways, here it is, and good luck!

(oh, and let me know if you have any critiques or comments or questions)

var $newTask = $("#new-task");
var $incompletedTasks = $("#incomplete-tasks");
var $completedTasks = $("#completed-tasks");
var $addButton = $("#add-button");

//generate a new list item
var makeNewListItem = function(taskToAdd) {

  var $newListItem = $("<li></li>");
  var $newCheckbox = $("<input type='checkbox' class='checkbox'>");
  var $newLabel = $("<label></label>");
  var $newEditInput = $("<input type='text' class='edit-text'>");
  var $newEditButton = $("<button class='edit-button'>Edit</button>");
  var $newDeleteButton = $("<button class='delete-button'>Delete</button>");

  $newListItem.append($newCheckbox)
  .append($newLabel.html(taskToAdd))
  .append($newEditInput)
  .append($newEditButton)
  .append($newDeleteButton);

  return $newListItem;
}

//add new list item to To-Do list when add-button is clicked.
$addButton.on( "click", function(){
  //the value of the new task is passed as an argument in the makeNewListItem function; a new list item is returned and stored as the variable of listItemToAdd
  var listItemToAdd = makeNewListItem($newTask.val());
  //append the new list item to the "To Do" list 
  $incompletedTasks.append(listItemToAdd);
  //clears the text in the "add item" input after task is added
  $newTask.val("");
})

//remove a task from the "To-Do" list when the delete button is clicked
$incompletedTasks.on( "click", ".delete-button", function(){
  $(this).parent().remove();  
})

//remove a task from the "Completed" list when the delete button is clicked
$completedTasks.on( "click", ".delete-button", function(){
  $(this).parent().remove();  
})

//function to edit tasks
var editTask = function (list, input, label){
 //if the list has the class of edit mode
  if (list.hasClass("editMode")) {
    //removes "editMode" class 
    list.removeClass("editMode");
    //makes the label's text the same as the input value
    label.text(input.val());
  } else {
    //adds the "editMode" class
    list.addClass("editMode");
    //makes the input's value the same as the label's text 
    input.val(label.text());
  }
}

//when you click on the "edit button" in the "To-Do" list.... 
$incompletedTasks.on( "click", ".edit-button", function(){
  //the list of the clicked on task
  var $list = $(this).parent();  
  //the input of the clicked on task
  var $input = $(this).prev();
  //the label of the clicked on task
  var $label = $input.prev();
  //the list, input, and label are passed to the editTask function
  editTask($list, $input, $label);
})

//when you click on the "edit button" in the "Completed" list.... 
$completedTasks.on( "click", ".edit-button", function(){
  var $list = $(this).parent();  
  var $input = $(this).prev();
  var $label = $input.prev();
  editTask($list, $input, $label);
})

//when you click on the checkbox in the "To-Do" list...
$incompletedTasks.on( "click", "input.checkbox", function(){
 //the list item of the checkbox 
 var listItem = $(this).parent();
 //appends the list item to the "Completed" list
 $completedTasks.append(listItem);
})

//when you click on the checkbox in the "Completed" list...
$completedTasks.on( "click", "input.checkbox", function(){
 //the list item of the checkbox 
 var listItem = $(this).parent();
 //appends the list item to the "To-Do" list
 $incompletedTasks.append(listItem);
})

And here is the HTML, which also has changes

<!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 id="add-button">Add</button>
      </p>

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

      </ul>

      <h3>Completed</h3>
      <ul id="completed-tasks">
        <li><input type="checkbox" class="checkbox"checked><label>See the Doctor</label><input type="text" class = 'edit-text'><button class="edit-button">Edit</button><button class="delete-button">Delete</button></li>
      </ul>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>