Skip to content

Lab: Todo App

ใน lab นี้คุณจะสร้าง todo app ที่ทำงานได้จริง — เพิ่ม, ลบ, toggle complete และเก็บข้อมูลใน localStorage

<!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>
  1. โครงสร้างข้อมูล

    สร้าง array todos โดยแต่ละ todo มี { id, text, done } — load จาก localStorage ถ้ามี

  2. Render function

    เขียน renderTodos() ที่สร้าง HTML จาก todos array แล้วใส่ใน #todo-list

  3. เพิ่ม todo

    ฟัง event submit ของ form แล้วเพิ่ม todo ใหม่เข้า array

  4. Toggle complete & ลบ

    ใช้ event delegation บน #todo-list เพื่อ toggle done status และลบ todo

  5. บันทึกลง localStorage

    เรียก save ทุกครั้งที่ข้อมูลเปลี่ยน

Show Solution
// === app.js ===
// Step 1: โครงสร้างข้อมูล + load จาก localStorage
let todos = JSON.parse(localStorage.getItem("todos")) || [];
// Helper: save to localStorage
function saveTodos() {
localStorage.setItem("todos", JSON.stringify(todos));
}
// Step 2: Render function
function 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: เพิ่ม todo
const 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 render
renderTodos();

ฟีเจอร์ที่ได้:

  • เพิ่ม todo ด้วย form submit
  • Toggle done/undone ด้วย checkbox
  • ลบ todo ด้วยปุ่มลบ
  • ข้อมูลคงอยู่ใน localStorage แม้ refresh หน้า
  • Event delegation สำหรับ dynamic elements