'Writing the most recently added element to the filtered to-do list
In my to-do list project, I have a function where I filter the things that have been done and the things that will be done. However, when I want to add a new element to the list, new ones also come with pre-filtered list elements. What should I do to make only the newly added code work when an addition occurs during filtering?
form.addEventListener("submit", function(e) {
e.preventDefault();
const value = document.getElementById("add-input").value;
const newItem = {
title: value,
id: Math.random().toString(36).substring(2, 10),
isDone: false,
};
todos.push(newItem);
localStorage.setItem("todos", JSON.stringify(todos));
section.innerHTML = todos.map((item) => todoItem(item)).join("");
document.getElementById("add-input").value = "";
});
filtered.addEventListener("change", function(e) {
let filteredTodos = todos;
if (e.target.value === "done") {
filteredTodos = todos.filter((item) => item.isDone === true);
}
if (e.target.value === "todo") {
filteredTodos = todos.filter((item) => item.isDone === false);
}
section.innerHTML = filteredTodos.map((item) => todoItem(item)).join("");
});
<form id="todo-form">
<input required id="add-input" type="text" placeholder="Bir yapılacak nesnesi ekleyin.." />
<button id="add-btn" type="submit">Ekle</button>
</form>
<section id="filter-list">
<div id="filter-title">Filtrele:</div>
<select id="dropdown">
<option value="all">Tümü</option>
<option value="todo">Yapılacak</option>
<option value="done">Yapıldı</option>
</select>
</section>
Solution 1:[1]
A good start would be to isolate all logic for creating your todo list in a render function. Whenever you change something in the internal state of your app, you call the render function and you can be sure the outcomes are consistent.
Here's a minimal change to make that work:
// Setup
const form = document.querySelector("form");
const filter = document.getElementById("dropdown");
const newTodoInput = document.getElementById("add-input");
const section = document.querySelector("ul");
const todoItem = ({ title, isDone, id }) => `<li> ${isDone ? `<s>${title}</s>` : title}</li>`;
// State
const todos = [ { title: "Fix code snippet", isDone: true, id: "1" }, { title: "Write own front-end framework", isDone: false, id: "2" } ];
// Render logic
const renderTodos = () => {
let filteredTodos = todos;
// Apply current filter
const filterValue = filter.value;
if (filterValue === "done") {
filteredTodos = todos.filter((item) => item.isDone === true);
}
if (filterValue === "todo") {
filteredTodos = todos.filter((item) => item.isDone === false);
}
// Render to page
section.innerHTML = filteredTodos.map((item) => todoItem(item)).join("");
}
form.addEventListener("submit", function(e) {
e.preventDefault();
const value = document.getElementById("add-input").value;
const newItem = {
title: value,
id: Math.random().toString(36).substring(2, 10),
isDone: false,
};
todos.push(newItem);
document.getElementById("add-input").value = "";
renderTodos();
});
filter.addEventListener("change", renderTodos);
// Initial render
renderTodos();
<form id="todo-form">
<input required id="add-input" type="text" placeholder="What do you need to do?" />
<button id="add-btn" type="submit">Create</button>
</form>
<section id="filter-list">
<div id="filter-title">Filter:</div>
<select id="dropdown">
<option value="all">All</option>
<option value="todo">To do</option>
<option value="done">Done</option>
</select>
</section>
<ul>
</ul>
If your app keeps on growing, it might be worth it to strictly separate state from UI. For example, you could store the value of your filter in javascript, and in your render function ensure the dropdown is in sync. That'd allow you to easily reset a filter in JS and just call render to have it show up in UI.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | user3297291 |
