Lab: Todo App
Lab: Todo App
Section titled “Lab: Todo App”ใน lab นี้คุณจะสร้าง todo app ที่ทำงานได้จริง — เพิ่ม, ลบ, toggle complete และเก็บข้อมูลใน localStorage
HTML เริ่มต้น
Section titled “HTML เริ่มต้น”<!DOCTYPE html><html lang="th"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Todo App</title> <style> body { font-family: sans-serif; max-width: 500px; margin: 2rem auto; } .done { text-decoration: line-through; opacity: 0.6; } .todo-item { display: flex; gap: 0.5rem; align-items: center; padding: 0.5rem 0; } </style></head><body> <h1>Todo List</h1> <form id="todo-form"> <input type="text" id="todo-input" placeholder="เพิ่ม todo..." required> <button type="submit">เพิ่ม</button> </form> <div id="todo-list"></div> <script src="app.js"></script></body></html>-
โครงสร้างข้อมูล
สร้าง array
todosโดยแต่ละ todo มี{ id, text, done }— load จาก localStorage ถ้ามี -
Render function
เขียน
renderTodos()ที่สร้าง HTML จาก todos array แล้วใส่ใน#todo-list -
เพิ่ม todo
ฟัง event
submitของ form แล้วเพิ่ม todo ใหม่เข้า array -
Toggle complete & ลบ
ใช้ event delegation บน
#todo-listเพื่อ toggle done status และลบ todo -
บันทึกลง localStorage
เรียก save ทุกครั้งที่ข้อมูลเปลี่ยน
Solution
Section titled “Solution”Show Solution
// === app.js ===
// Step 1: โครงสร้างข้อมูล + load จาก localStoragelet todos = JSON.parse(localStorage.getItem("todos")) || [];
// Helper: save to localStoragefunction saveTodos() { localStorage.setItem("todos", JSON.stringify(todos));}
// Step 2: Render functionfunction renderTodos() { const list = document.querySelector("#todo-list");
if (todos.length === 0) { list.innerHTML = "<p>ไม่มี todo — เพิ่มได้เลย!</p>"; return; }
list.innerHTML = todos .map( (todo) => ` <div class="todo-item" data-id="${todo.id}"> <input type="checkbox" ${todo.done ? "checked" : ""}> <span class="${todo.done ? "done" : ""}">${todo.text}</span> <button class="delete-btn">ลบ</button> </div> ` ) .join("");}
// Step 3: เพิ่ม todoconst form = document.querySelector("#todo-form");const input = document.querySelector("#todo-input");
form.addEventListener("submit", (event) => { event.preventDefault();
const text = input.value.trim(); if (!text) return;
todos.push({ id: Date.now(), text, done: false, });
input.value = ""; saveTodos(); renderTodos();});
// Step 4: Toggle & Delete (Event Delegation)document.querySelector("#todo-list").addEventListener("click", (event) => { const todoItem = event.target.closest(".todo-item"); if (!todoItem) return;
const id = Number(todoItem.dataset.id);
// Toggle checkbox if (event.target.type === "checkbox") { const todo = todos.find((t) => t.id === id); if (todo) todo.done = !todo.done; saveTodos(); renderTodos(); }
// Delete button if (event.target.matches(".delete-btn")) { todos = todos.filter((t) => t.id !== id); saveTodos(); renderTodos(); }});
// Initial renderrenderTodos();ฟีเจอร์ที่ได้:
- เพิ่ม todo ด้วย form submit
- Toggle done/undone ด้วย checkbox
- ลบ todo ด้วยปุ่มลบ
- ข้อมูลคงอยู่ใน localStorage แม้ refresh หน้า
- Event delegation สำหรับ dynamic elements