Cấp độ: intermediate50 phútminMiễn phíFreeProduct DeveloperProduct Developer

Full-stack: Ứng dụng TodoFull-stack: Todo application

Ứng dụng Todo full-stack có databaseA full-stack Todo app with database

Bạn sẽ học gìWhat you will learn

  • Kết nối frontend với backend APIConnect frontend to backend API
  • Lưu dữ liệu vào SQLiteSave data to SQLite
  • Xây UI update không reload trangBuild UI that updates without reload

Bạn sẽ tạo gìWhat you will build

Ứng dụng Todo full-stack có databaseA full-stack Todo app with database

Nội dung bài họcLesson content

Full-stack là gì?What is full-stack?

Full-stack là kết hợp frontend (giao diện người dùng — HTML/CSS/JS), backend (logic server — Node.js/Express) và database (lưu trữ — SQLite). Ứng dụng Todo full-stack: user thêm/sửa/xóa task trên web → frontend gọi API → backend xử lý → lưu database.Full-stack combines frontend (user interface — HTML/CSS/JS), backend (server logic — Node.js/Express), and database (storage — SQLite). A full-stack Todo app: user adds/edits/deletes tasks on web → frontend calls API → backend processes → saves to database.

Frontend gọi API với fetch()Frontend calls API with fetch()

fetch(url, options) là hàm JavaScript gọi API. GET: fetch("/tasks"). POST: fetch("/tasks", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) }). fetch trả Promise — dùng await hoặc .then() để lấy response.fetch(url, options) is the JavaScript function to call APIs. GET: fetch("/tasks"). POST: fetch("/tasks", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) }). fetch returns a Promise — use await or .then() to get the response.

javascript
                      
                        // GET: lấy danh sách task
async function loadTasks() {
  const res = await fetch('/tasks');
  const data = await res.json();
  renderTasks(data.data);
}

// POST: tạo task mới
async function addTask(title) {
  const res = await fetch('/tasks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title })
  });
  const data = await res.json();
  loadTasks();  // Tải lại danh sách
}
                      
                    

Cập nhật UI không reload trangUpdating UI without page reload

Khi thêm task, không cần reload trang. Dùng JavaScript: tạo element mới, thêm vào DOM. element.innerHTML hoặc document.createElement + appendChild. Đây là cách SPA (Single Page Application) hoạt động — mượt mà, nhanh.When adding a task, no need to reload the page. Use JavaScript: create a new element, add to DOM. element.innerHTML or document.createElement + appendChild. This is how SPAs (Single Page Applications) work — smooth and fast.

javascript
                      
                        function renderTasks(tasks) {
  const list = document.querySelector('#task-list');
  list.innerHTML = '';  // Xóa cũ
  tasks.forEach(task => {
    const li = document.createElement('li');
    li.textContent = task.title;
    if (task.done) li.classList.add('done');
    list.appendChild(li);
  });
}
                      
                    

Backend lưu vào SQLiteBackend saves to SQLite

Backend nhận request, thực hiện SQL query lên SQLite, trả response. Dùng better-sqlite3 (đồng bộ) hoặc sqlite3 (callback). Mỗi endpoint tương ứng 1 SQL operation: GET → SELECT, POST → INSERT, PUT → UPDATE, DELETE → DELETE.The backend receives requests, executes SQL queries on SQLite, returns responses. Use better-sqlite3 (synchronous) or sqlite3 (callback). Each endpoint corresponds to a SQL operation: GET → SELECT, POST → INSERT, PUT → UPDATE, DELETE → DELETE.

javascript
                      
                        const Database = require('better-sqlite3');
const db = new Database('todo.db');

db.exec(`CREATE TABLE IF NOT EXISTS tasks (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  done INTEGER DEFAULT 0
)`);

app.get('/tasks', (req, res) => {
  const tasks = db.prepare('SELECT * FROM tasks').all();
  res.json({ success: true, data: tasks });
});

app.post('/tasks', (req, res) => {
  const info = db.prepare('INSERT INTO tasks (title) VALUES (?)').run(req.body.title);
  res.status(201).json({ success: true, data: { id: info.lastInsertRowid, title: req.body.title } });
});
                      
                    

Bài tập thực hànhHands-on exercises

1Tạo frontend HTML có input + button "Thêm". Khi click, gọi POST /tasks với title từ input.Create HTML frontend with input + "Add" button. On click, call POST /tasks with title from input.

Gợi ýHint

addEventListener("click") → fetch POST với body JSON.addEventListener("click") → fetch POST with JSON body.

Lời giảiSolution
html
                      
                        <input id="task-input" placeholder="Tên task">
<button id="add-btn">Thêm</button>
<ul id="task-list"></ul>

<script>
document.querySelector('#add-btn').addEventListener('click', async () => {
  const title = document.querySelector('#task-input').value;
  await fetch('/tasks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title })
  });
  loadTasks();
});
</script>
                      
                    

2Thêm endpoint DELETE /tasks/:id trong backend để xóa task khỏi SQLite.Add endpoint DELETE /tasks/:id in backend to delete a task from SQLite.

Gợi ýHint

app.delete('/tasks/:id', ...) → db.prepare("DELETE FROM tasks WHERE id = ?").run(id)app.delete('/tasks/:id', ...) → db.prepare("DELETE FROM tasks WHERE id = ?").run(id)

Lời giảiSolution
javascript
                      
                        app.delete('/tasks/:id', (req, res) => {
  const id = req.params.id;
  db.prepare('DELETE FROM tasks WHERE id = ?').run(id);
  res.json({ success: true, message: 'Đã xóa' });
});
                      
                    

Kiểm traQuiz

Chọn đáp án đúng cho mỗi câu. Nhấn để xem giải thích.Choose the correct answer for each question. Click to see explanation.

Câu 1: Full-stack bao gồm những phần nào?Q1: What does full-stack include?

Câu 2: Hàm fetch() trong JavaScript dùng để làm gì?Q2: What is the fetch() function in JavaScript used for?

Câu 3: SPA (Single Page Application) là gì?Q3: What is a SPA (Single Page Application)?