Filtering Todos
Selecting a Filter
The anchor elements in the navbar act as filters to display all todos, active todos, or completed todos. We will add an event listener to the navbar and create a function to handle the filter selection.
// Function to handle filter selection from the navbar
function handleClickOnNavbar(event) {
// if the clicked element is an anchor tag
if (event.target.tagName === "A") {
const hrefValue = event.target.href;
const action = hrefValue.split("/").pop();
filter = action === "" ? "all" : action;
console.log(filter);
}
}
const todoNav = document.getElementById("todo-nav");
todoNav.addEventListener("click", handleClickOnNavbar);
Let’s break down the handleClickOnNavbar function:
-
Checking the Clicked Element:
if (event.target.tagName === "A") {We check if the clicked element is an anchor tag (
<a>). This condition ensures that the function only runs when the user clicks on one of the filter links. -
Extracting the Filter Action:
const hrefValue = event.target.href; const action = hrefValue.split("/").pop(); filter = action === "" ? "all" : action;We extract the
hrefattribute of the clicked anchor element (event.target.href) to get the URL. We then split the URL by the`/`character and extract the last part of the URL usingpop(). This part corresponds to the filter action (e.g.,all,active, orcompleted). If the action is an empty string, we set the filter to'all'.
Aside: We could have added the click event to each anchor element and handled the filter selection for each. Instead, we chose to add the event listener to the parent element (todoNav) and use event delegation to handle the filter selection.
Rendering Filtered Todos
We can update the renderTodos function to filter the todos based on the current filter setting like this:
// Filter todos based on the current filter setting
let filteredTodos = [];
for (let i = 0; i < todos.length; i++) {
const todo = todos[i];
if (filter === "all") {
filteredTodos.push(todo);
} else if (filter === "completed" && todo.completed) {
filteredTodos.push(todo);
} else if (filter === "active" && !todo.completed) {
filteredTodos.push(todo);
}
}
Next we will update the loop that renders the todos to use the filteredTodos array instead of the todos array.
// Loop through the filtered todos and add them to the DOM
- for (let i = 0; i < todos.length; i++) {
+ for (let i = 0; i < filteredTodos.length; i++) {
- const todo = todos[i];
+ const todo = filteredTodos[i];
// code not shown for brevity
}
Make sure to call renderTodos after updating the filter to display the filtered todos.
// Function to handle filter selection from the navbar
function handleClickOnNavbar(event) {
// if the clicked element is an anchor tag
if (event.target.tagName === "A") {
const hrefValue = event.target.href;
const action = hrefValue.split("/").pop();
filter = action === "" ? "all" : action;
- console.log(filter);
+ renderTodos();
}
}
Run the app and check if the todos are filtered correctly based on the selected filter.
Styling the Active Filter
Right now the first anchor element in the navbar has an underline style, and that style is hardcoded in the HTML file. Let’s create a new function, renderTodoNavBar, to apply the style based on the selected filter instead.
// Function to update the navbar anchor elements
function renderTodoNavBar(href) {
const elements = todoNav.children;
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
if (element.href === href) {
element.classList.add(
"underline",
"underline-offset-4",
"decoration-rose-800",
"decoration-2",
);
} else {
element.classList.remove(
"underline",
"underline-offset-4",
"decoration-rose-800",
"decoration-2",
);
}
}
}
This function iterates over the child elements of the todoNav element (the navbar) and applies or removes the underline style based on the href value. The anchor element that matches the href value gets the underline style applied, while the others have it removed.
Now call this function after updating the filter in the handleClickOnNavbar function.
// Function to handle filter selection from the navbar
function handleClickOnNavbar(event) {
// if the clicked element is an anchor tag
if (event.target.tagName === "A") {
const hrefValue = event.target.href;
const action = hrefValue.split("/").pop();
filter = action === "" ? "all" : action;
renderTodos();
+ renderTodoNavBar(hrefValue);
}
}
Run the app and check if the active filter is styled correctly based on the selected filter.
Checkpoint: Commit your progress.
git add .
git commit -m "todos-08: Implement todo filtering"
git push