Open In App

JavaScript Course Task Tracker Project

Improve
Improve
Like Article
Like
Save
Share
Report

In this final article of this course, we will learn how to make a simple javascript application where we can add tasks, delete tasks and edit them too. Pure(Vanilla) JavaScript has been used and we will also make use of DOM manipulation a lot so one of the main prerequisites is HTML | DOM.

Project Structure:

index.html
styles.css
list.js

Project Preview:

Course Tracker Project

Example: In this example code, we have built the course tracker project using javascript.

HTML




<!DOCTYPE html>
<html>
 
<head>
    <title>Task Tracker</title>
    <link rel="stylesheet" href="styles.css" type="text/css" media="screen" charset="utf-8"
</head>
 
<body>
    <div class="container">
        <p>
            <label for="new-task" class="middle">Add Task</label>
            <input id="new-task" type="text">
            <button>Add Task</button>
        </p>
        <h3 class="middle">Todo</h3>
        <ul id="incomplete-tasks">
        </ul>
        <h3 class="middle">Completed Tasks</h3>
        <ul id="completed-tasks">
        </ul>
    </div>
    <script type="text/javascript" src="list.js"></script>
     
</body>
 
</html>


CSS




/* Basic Style */
   body {
       background: #ecf0f1;
       color: #333;
       font-family: Lato, sans-serif;
   }
 
   .container {
       display: block;
       width: 500px;
       margin: 50px auto 0;
   }
 
   ul {
       margin: 0;
       padding: 0;
   }
 
   li * {
       float: left;
   }
 
   li,
   h3 {
       clear: both;
       list-style: none;
   }
 
   input,
   button {
       outline: none;
   }
 
   button {
       background: none;
       border: 0;
       color: #888;
       font-size: 15px;
       width: 100px;
       margin: 10px 0 0;
       font-family: Lato, sans-serif;
       cursor: pointer;
   }
 
   button:hover {
       color: #333;
   }
 
   /* Heading */
   h3,
   label[for='new-task'] {
       color: #333;
       font-weight: 700;
       font-size: 15px;
       border-bottom: 2px solid #333;
       padding: 30px 0 10px;
       margin: 0;
       text-transform: uppercase;
   }
 
   input[type="text"] {
       margin: 0;
       font-size: 18px;
       line-height: 18px;
       height: 18px;
       padding: 10px;
       border: 1px solid #ddd;
       background: #fff;
       border-radius: 6px;
       font-family: Lato, sans-serif;
       color: #888;
   }
 
   input[type="text"]:focus {
       color: #333;
   }
 
   .middle {
       text-align: center;
   }
 
 
   /* New Task */
   label[for='new-task'] {
       display: block;
       margin: 0 0 20px;
   }
 
   input#new-task {
       float: right;
       width: 318px;
   }
 
   p>button:hover {
       color: #0FC57C;
   }
 
   /* Task list */
   li {
       overflow: hidden;
       padding: 20px 0;
       border-bottom: 1px solid #eee;
   }
 
   li>input[type="checkbox"] {
       margin: 0 10px;
       position: relative;
       top: 15px;
   }
 
   li>label {
       font-size: 18px;
       line-height: 40px;
       width: 237px;
       padding: 0 0 0 11px;
   }
 
   li>input[type="text"] {
       width: 226px;
   }
 
   li>.delete:hover {
       color: #CF2323;
   }
 
   /* Completed */
   #completed-tasks label {
       text-decoration: line-through;
       color: #888;
   }
 
   /* Edit Task */
   ul li input[type=text] {
       display: none;
   }
 
   ul li.editMode input[type=text] {
       display: block;
   }
 
   ul li.editMode label {
       display: none;
   }


Javascript




// Add a new task.
  let taskInput = document.getElementById("new-task");
 
  // first button
  let addButton = document.getElementsByTagName("button")[0];
 
  // ul of #incomplete-tasks
  let incompleteTaskHolder = document.getElementById("incomplete-tasks");
 
  // completed-tasks
  let completedTasksHolder = document.getElementById("completed-tasks");
 
  /*---- Part 1 ----*/
  // function to create a new task item
  let createNewTaskElement = function (taskString) {
 
      let listItem = document.createElement("li");
 
      // input (checkbox)
      let checkBox = document.createElement("input");
      // label
      let label = document.createElement("label");
      // input (text)
      let editInput = document.createElement("input");
      // button.edit
      let editButton = document.createElement("button");
 
      // button.delete
      let deleteButton = document.createElement("button");
 
      label.innerText = taskString;
 
      // Each element needs appending
      checkBox.type = "checkbox";
      editInput.type = "text";
 
 
      // innerText encodes special characters, HTML does not.
      editButton.innerText = "Edit";
      editButton.className = "edit";
      deleteButton.innerText = "Delete";
      deleteButton.className = "delete";
 
      // Append elements
      listItem.appendChild(checkBox);
      listItem.appendChild(label);
      listItem.appendChild(editInput);
      listItem.appendChild(editButton);
      listItem.appendChild(deleteButton);
      return listItem;
  }
  /*---- Part 2 ----*/
  let addTask = function () {
 
      let listItem = createNewTaskElement(taskInput.value);
 
      if (taskInput.value === "") {
          return;
      }
 
      // Append listItem to incompleteTaskHolder
      incompleteTaskHolder.appendChild(listItem);
      bindTaskEvents(listItem, taskCompleted);
 
      taskInput.value = "";
 
  }
 
  /*---- Part 3 ----*/
  let editTask = function () {
      let listItem = this.parentNode;
 
      let editInput = listItem.querySelector('input[type=text]');
      let label = listItem.querySelector("label");
      let containsClass = listItem.classList.contains("editMode");
      // If class of the parent is .editmode
      if (containsClass) {
          label.innerText = editInput.value;
      } else {
          editInput.value = label.innerText;
      }
      listItem.classList.toggle("editMode");
  }
 
  /*---- Part 4 ----*/
  let deleteTask = function () {
 
      let listItem = this.parentNode;
      let ul = listItem.parentNode;
      // Remove the parent list item from the ul.
      ul.removeChild(listItem);
 
  }
 
  /*---- Part 5 ----*/
 
  let taskCompleted = function () {
 
      // Append the task list item to the #completed-tasks
      let listItem = this.parentNode;
      completedTasksHolder.appendChild(listItem);
      bindTaskEvents(listItem, taskIncomplete);
 
  }
 
  /*---- Part 6 ----*/
  let taskIncomplete = function () {
      // Mark task as incomplete.
      // When the checkbox is unchecked
      // Append the task list item to the #incomplete-tasks.
      let listItem = this.parentNode;
      incompleteTaskHolder.appendChild(listItem);
      bindTaskEvents(listItem, taskCompleted);
 
  }
 
  /*---- Part 7 ----*/
  let bindTaskEvents = function (taskListItem, checkBoxEventHandler) {
 
      // select taskListItem's children
      let checkBox = taskListItem.querySelector("input[type=checkbox]");
      let editButton = taskListItem.querySelector("button.edit");
      let deleteButton = taskListItem.querySelector("button.delete");
 
      // bind editTask to edit button
      editButton.onclick = editTask;
      // bind deleteTask to delete button
      deleteButton.onclick = deleteTask;
      // bind checkBoxEventHandler to checkbox
      checkBox.onchange = checkBoxEventHandler;
  }
 
  /*---- Part 8 ----*/
  // Set the click handler to the addTask function
  addButton.addEventListener("click", addTask);
  addButton.addEventListener("click", ajaxRequest);
 
  /*---- Part 9 ----*/
  // Cycle over incompleteTaskHolder ul list items
  for (let i = 0; i < incompleteTaskHolder.children.length; i++) {
      // bind events to list item's children (taskCompleted)
      bindTaskEvents(incompleteTaskHolder.children[i], taskCompleted);
  }
 
  /*---- Part 10 ----*/
  // Cycle over completedTasksHolder ul list items
  for (let i = 0; i < completedTasksHolder.children.length; i++) {
      // bind events to list item's children (taskIncomplete)
      bindTaskEvents(completedTasksHolder.children[i], taskIncomplete);
  }


Output: Click here to see live code output

JavaScript Course Task Tracker Project

JavaScript Course Task Tracker Project

Explanation: 

The above HTML code contains simple list tags and one text field which we will populate with text when we add, or delete tasks. Certain classes are assigned which we make use of while getting that particular element by DOM or by styling it inside the styles.css file. All the above content is inside a div with the class ‘container’ that has its own styling and attributes.

Explanation

Part 1: The way this function works is that it takes the ‘inputString’ i.e. the text that we pass inside the HTML text field as a task and then it creates several elements using DOM properties and appends their specific classes. After appending we insert all the elements inside the list as listItems.
Part 2: This addTask function is called when we click the button ‘addButton'(line 115) and then inside it we create a listItem with the value the user entered and then check the value, as it must not be an empty string then we simply add the above value inside the ‘inputTaskHolder’ and finally setting the value inside it as an empty string before calling the ‘bindFunction’.

Part 3: This code function is used to edit an existing task and we do so by keeping track of the parent node and then a simple if-else check whether the ‘editMode’ button is clicked or not if clicked then simply assign the value of the label innerText to value inside the editInput, if not then vice versa. Then after editing, we toggle the value of the ‘editMode’ as we have edited.

Part 4: In this part, we delete a task, and the way we do it is by making use of the parent node of the current node and then storing the parent of the parent node, and then simply deleting the child of this node.

Part 5: In this function, we mark the task as complete by simply appending the child of the parent node inside completeTaskHolder element and then calling the bindFunction.

Part 6:In this function, we mark the task as incomplete by simply appending the child of the parent node inside inCompleteTaskHolder element and then calling the bindFunction.

Part 7: In this part, we call the BindFunction where we respond to several user interaction activities and make several buttons work.

Part 8: In this final section, we iterate over several parts binding children with the help of for loop inside the incomplete and complete TaskHolder element.



Last Updated : 06 Jun, 2023
Like Article
Save Article
Share your thoughts in the comments
Similar Reads