- vừa được xem lúc

Tạo Smart Forms mà không cần JavaScript – "Phép màu" của HTML và AJAX

0 0 5

Người đăng: Nam Phạm

Theo Viblo Asia

Khi nói đến xây dựng form trên web, hầu hết lập trình viên sẽ nghĩ ngay đến việc sử dụng JavaScript — đôi khi là kết hợp với các framework như React hoặc Vue. Tuy nhiên, trong bài viết này, bạn sẽ thấy cách để tạo một smart form chỉ với HTML thuần và một chút hỗ trợ từ HMPL, mà hoàn toàn không cần viết JavaScript tùy chỉnh.

alt

Cấu trúc dự án

Dự án mẫu có cấu trúc thư mục như sau:

📁 smart-form
├── 📁 components
│ └── 📁 Register
│ └── index.html
├── 📁 src
│ ├── global.css
│ ├── global.js
│ └── index.html
├── app.js
└── routes └── post.js

Chúng ta sử dụng:

Server: Node.js + Express để xử lý route và phản hồi

Frontend: HTML, CSS thuần và HMPL để render component, trigger request động mà không dùng JavaScript truyền thống

Css cho Form

Hãy bắt đầu với giao diện đơn giản

body { font-family: Arial, sans-serif; background: #f4f4f4; padding: 50px;
} form { background: white; padding: 20px; border-radius: 6px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); max-width: 400px; margin: auto;
} .form-example { margin-bottom: 15px;
} label { display: block; margin-bottom: 5px;
} input[type="text"],
input[type="password"] { width: 100%; padding: 8px; box-sizing: border-box;
} input[type="submit"] { background-color: #649606; color: white; border-radius: 5px; padding: 10px 15px; cursor: pointer;
}

Thiết lập API

Tạo một Express server với route POST để submit Form

const express = require("express");
const path = require("path");
const cors = require("cors"); const app = express();
const PORT = 8000; app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json()); app.use(express.static(path.join(__dirname, "src"))); const postRoutes = require("./routes/post");
app.use("/api", postRoutes); app.get("/", (_, res) => { res.sendFile(path.join(__dirname, "src/index.html"));
}); app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`);
});
const express = require("express");
const router = express.Router(); router.post("/register", (req, res) => { const { login, password } = req.body; if (!login || !password) { return res.status(400).send("<p style='color: red;'>Missing fields!</p>"); } console.log("User Registered:", login); res.send(`<p style='color: green;'>Welcome, ${login}!</p>`);
}); module.exports = router;

Tạo form động không dùng JavaScript

Form này sẽ gửi dữ liệu bằng cách sử dụng request block của HMPL, mà không cần viết bất kỳ sự kiện JavaScript nào.

<div> <form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form"> <div class="form-example"> <label for="login">Login:</label> <input type="text" name="login" id="login" required /> <br/> <label for="password">Password:</label> <input type="password" name="password" id="password" required /> </div> <div class="form-example"> <input type="submit" value="Register!" /> </div> </form> <p> {{#request src="/api/register" after="submit:#form" repeat=false indicators=[ { trigger: "pending", content: "<p>Loading...</p>" } ] }} {{/request}} </p>
</div>

Phân tích

  • onsubmit: Ngăn reload trang khi submit
  • #request: Cấu trúc đặc biệt từ HMPL để thực hiện AJAX call
  • after="submit:#form": Trigger gọi API sau sự kiện submit
  • indicators: Hiển thị trạng thái phản hồi (pending/loading)

📌 Không cần fetch, không cần async/await, không cần viết JavaScript thêm! Tất cả đều qua cú pháp của HMPL.

Sử dụng Component với HMPL

Sử dụng component trên bằng HMPL

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Smart Form</title> <link rel="stylesheet" href="global.css" /> </head> <body> <div id="wrapper"></div> <script src="https://unpkg.com/json5/dist/index.min.js"></script> <script src="https://unpkg.com/dompurify/dist/purify.min.js"></script> <script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script> <script> import { compile } from "hmpl-js"; const templateFn = compile(` {{#request src="/components/Register/index.html"}}{{/request}} `); const obj = templateFn(); document.getElementById("wrapper").append(obj.response); </script> </body>
</html>

Có thể tách logic này thành một tệp global.js riêng nếu muốn đảm bảo tính module.

Kết quả

  • Một Form đơn giản
  • Gửi dữ liệu bất đồng bộ chỉ với HTML + HMPL
  • Validate và trả về result — tất cả không cần logic JavaScript tùy chỉnh

alt

Tại sao chọn cách này?

  • Không cần framework JavaScript: Không React, không Angular.
  • Bạn mô tả điều gì sẽ xảy ra, không cần cách thực hiện.
  • Đơn giản và có thể mở rộng: Phù hợp cho landing pages, admin tools và MVPs.
  • Bạn thậm chí có thể mở rộng mô hình này để hỗ trợ multi-step forms, loaders, xử lý lỗi hoặc tự động lưu theo khoảng thời gian định kỳ.

Kết luận

HMPL là một giải pháp đơn giản nhưng mạnh mẽ cho những ai muốn xây dựng ứng dụng web có khả năng tương tác mà không cần phụ thuộc vào JavaScript. Đặc biệt, với những dự án yêu cầu tối ưu hóa hiệu năng, hoặc khi bạn muốn hạn chế client-side scripting, HMPL là một lựa chọn rất đáng cân nhắc.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Hướng dẫn finetune mô hình LLM đơn giản và miễn phí với Unsloth

Chào mừng các bạn đến với bài viết hướng dẫn chi tiết cách finetune (tinh chỉnh) một mô hình ngôn ngữ lớn (LLM) một cách đơn giản và hoàn toàn miễn phí sử dụng thư viện Unsloth. Trong bài viết này, ch

0 0 7

- vừa được xem lúc

SERIES INDEX NÂNG CAO - BÀI 1: PHÂN TÍCH NHỮNG SAI LẦM PHỔ BIẾN KHI SỬ DỤNG INDEX TRONG MYSQL

Nếu anh em thấy hay thì ủng hộ tôi 1 follow + 1 upvote + 1 bookmark + 1 comment cho bài viết này tại Mayfest 2025 nhé. Còn nếu bài viết chưa hữu ích thì tôi cũng hi vọng anh em để lại những góp ý thẳn

0 0 8

- vừa được xem lúc

"Hack" Não Số Lớn Với Digit DP!

Xin chào anh em, những chiến binh thuật toán kiên cường. Phản ứng đầu tiên của nhiều anh em (có cả tôi): "Ối dào, dễ! Quất cái for từ 1 đến 101810^{18}1018 rồi check thôi!".

0 0 10

- vừa được xem lúc

So Sánh StatelessWidget và StatefulWidget & Các Widget Nâng Cao

Chào mọi người! Hôm nay chúng ta sẽ tiếp tục hành trình khám phá Flutter và đến với bài học về StatelessWidget và StatefulWidget. Trong bài này, mình sẽ giúp các bạn phân biệt sự khác nhau giữa hai lo

0 0 7

- vừa được xem lúc

React Lifecycle & Hooks Cơ Bản

React cung cấp các phương thức lifecycle và hooks để quản lý các giai đoạn khác nhau trong vòng đời của component. Việc hiểu rõ các phương thức này giúp bạn có thể tối ưu hóa ứng dụng React của mình.

0 0 7

- vừa được xem lúc

Kafka Fundamental - Bài 4: Consumers, Deserialization, Consumer Groups & Consumer Offsets

Xin chào, lại là mình - Đức Phúc, anh chàng hơn 6 năm trong nghề vẫn nghèo technical nhưng thích viết Blog để chia sẻ kiến thức bản thân học được trong quá trình “cơm áo gạo tiền” đây. Các bạn có thể

0 0 5