Adding More Features

Marking All Todos as Completed

Let’s add a feature to mark all todos as completed. There is a button with the id mark-all-completed that we can use to trigger this action.

const markAllCompleted = document.getElementById("mark-all-completed");

// Event handler to mark all todos as completed
const handleMarkAllCompleted = () => {};

markAllCompleted.addEventListener("click", handleMarkAllCompleted);

Before implementing the handleMarkAllCompleted function, let’s think about the logic. We need to create a new array where every todo is marked as completed. We can use map for this:

// Helper function to mark all todos as completed
const markAllTodosCompleted = (todos) => {
  return todos.map((todo) => {
    return { ...todo, completed: true };
  });
};

Since this logic is only used inside the factory, we can inline it directly. Let’s add a markAllCompleted method to our factory function:

markAllCompleted: () => {
  todos = todos.map((todo) => ({ ...todo, completed: true }));
},

Now, we can implement the handleMarkAllCompleted function to mark all todos as completed.

// Event handler to mark all todos as completed
const handleMarkAllCompleted = () => {
  todoApp.markAllCompleted();
  renderTodos();
};

Run the code and test the “Mark All Completed” feature by clicking the “Mark All Completed” button. You should see all todos marked as completed.

Clearing Completed Todos

Let’s add a feature to clear all completed todos. There is a button with the id clear-completed that we can use to trigger this action.

const clearCompleted = document.getElementById("clear-completed");

// Event handler to clear all completed todos
const clearCompletedTodos = () => {};

clearCompleted.addEventListener("click", clearCompletedTodos);

Before implementing the clearCompletedTodos function, let’s think about the logic. We need to create a new array with all completed todos filtered out. We can use filter for this:

// Helper function to delete all completed todos
const deleteCompletedTodos = (todos) => {
  return todos.filter((todo) => !todo.completed);
};

Again, we can inline this logic directly into a new factory method:

deleteCompleted: () => {
  todos = todos.filter((todo) => !todo.completed);
},

Now, we can implement the clearCompletedTodos function to delete all completed todos.

// Event handler to clear all completed todos
const clearCompletedTodos = () => {
  todoApp.deleteCompleted();
  renderTodos();
};

Run the code and test the “Clear Completed” feature by clicking the “Clear Completed” button. You should see all completed todos removed from the list.

Displaying the Active Todos Count

There is a span element with the id todo-count that we can use to display the number of active todos. Let’s get hold of this element and update it with the count of active todos.

const activeTodosCount = document.getElementById("todo-count");

Next, let’s add a method to the factory function to get the number of active todos. We can use the reduce function to calculate this:

getNumberOfActiveTodos: () =>
  todos.reduce((acc, todo) => acc + !todo.completed, 0),

The reduce function takes an accumulator acc and the current todo item as arguments. For each todo item, it increments the accumulator by 1 if the todo is not completed. The initial value of the accumulator is set to 0.

Let’s update the renderTodos function to display the number of active todos.

// Function to render the todos based on the current filter
const renderTodos = () => {
  todoListElement.innerHTML = "";  // Clear the current list to avoid duplicates

  const todoElements = todoApp.getTodos().map(createTodoItem);
  todoListElement.append(...todoElements);

  activeTodosCount.textContent = `${todoApp.getNumberOfActiveTodos()} item${todoApp.getNumberOfActiveTodos() === 1 ? "" : "s"} left`;
};

We are using a template literal to build the text. It puts the count in, and it picks “item” or “items” depending on whether the count is 1.

Run the code and check the count of active todos. You should see it displayed on the screen.

Checkpoint: Commit your progress.

git add .
git commit -m "todos-14: Add mark all, clear completed, and active count features"
git push