Cách tạo form trong HTML
Form (biểu mẫu) là một phần tử <form> chứa các trường nhập và một nút gửi. Mỗi trường cần một name: đó là khóa mà giá trị được gửi kèm. Điền vào form rồi bấm Send. Bản xem trước không gửi dữ liệu đi đâu cả; nó hiện chính xác những gì trình duyệt lẽ ra đã gửi.
Các thành phần:
actionlà URL nhận dữ liệu, cònmethodlà cách gửi (ở đây làpost).nametrên mọi trường. Giá trị của trường là những gì người dùng đã gõ.<label>đặt tên cho từng trường trên màn hình và cho trình đọc màn hình (xem label trong HTML).requiredvàtype="email"khiến trình duyệt kiểm tra các trường trước khi gửi. Thử gửi khi để trống tên, hoặc nhậpabcvào ô email.- Nút submit gửi form. Nhấn Enter trong một ô văn bản cũng vậy.
action và method: dữ liệu đi đâu và đi thế nào
| Thuộc tính | Giá trị | Mặc định |
|---|---|---|
action | Một URL bất kỳ | URL của trang hiện tại |
method | get, post, dialog | get |
enctype | application/x-www-form-urlencoded, multipart/form-data, text/plain | application/x-www-form-urlencoded |
Với method="get", các trường trở thành query string của URL: một form tìm kiếm có name="q" sẽ đi tới /search?q=blue+shoes. Cách này đúng cho tìm kiếm và bộ lọc, vì kết quả có thể được lưu dấu trang và chia sẻ. Với method="post", các trường nằm trong phần thân của request và không hiện trên thanh địa chỉ hay trong lịch sử. Dùng POST cho mọi thao tác đăng nhập, tạo, sửa hoặc xóa dữ liệu, và cho mật khẩu.
Form có tải tệp lên (<input type="file">) cần method="post" và enctype="multipart/form-data", nếu không thì chỉ tên tệp được gửi. method="dialog" dành cho form nằm trong <dialog>: gửi form sẽ đóng hộp thoại thay vì gửi request.
Những gì được gửi đi
Chỉ những trường có name mới được gửi, và chỉ khi chúng không bị disabled. Bấm Submit rồi so sánh các trường với những gì form gửi đi:
Form gửi city, zip, source và action. Trường không có tên, trường bị vô hiệu hóa và checkbox chưa chọn đều bị bỏ ra. Input ẩn vẫn được gửi nhưng không bao giờ hiển thị, còn nút submit gửi name và value của chính nó vì đó là nút đã được bấm.
Nhóm trường bằng fieldset và legend
<fieldset> vẽ một khung quanh các trường liên quan, còn <legend> là tiêu đề của khung. Trình đọc màn hình đọc legend khi focus đi vào nhóm, nhờ vậy một bộ radio button như bên dưới mới dễ hiểu: "Delivery, Standard, radio button".
disabled trên fieldset vô hiệu hóa cùng lúc mọi trường bên trong, và không trường nào được gửi. Bỏ nó đi là các trường quà tặng dùng được.
Kiểm tra có sẵn: required, pattern và các thuộc tính khác
Trình duyệt kiểm tra các thuộc tính này trước khi gửi và hiện thông báo ở trường đầu tiên không đạt:
| Thuộc tính | Kiểm tra |
|---|---|
required | Trường không trống (checkbox đã được chọn) |
type="email", type="url" | Giá trị trông giống địa chỉ email hoặc URL |
minlength, maxlength | Độ dài văn bản |
min, max, step | Khoảng giá trị số và ngày |
pattern | Toàn bộ giá trị khớp với một biểu thức chính quy |
:invalid và :valid định dạng trường theo trạng thái của nó. :user-invalid thường tốt hơn: nó chỉ áp dụng sau khi người dùng đã sửa trường rồi rời đi, hoặc đã thử gửi form, nên một form trống không bị phủ đỏ ngay khi mở.
Có ba điều về pattern hay khiến người ta vấp. Nó phải khớp toàn bộ giá trị (không cần ^ hay $). Nó chỉ chạy khi trường không trống, nên hãy dùng kèm required. Và thông báo lỗi của trình duyệt rất chung chung, nên hãy mô tả định dạng bằng chữ hiển thị cạnh trường. Chrome và Firefox thêm nội dung title vào thông báo, nhưng rất dễ bị bỏ sót.
Để tắt các bước kiểm tra, ví dụ khi bạn thử phần kiểm tra trên máy chủ, hãy thêm novalidate vào <form>. Một nút submit riêng lẻ có thể bỏ qua chúng bằng formnovalidate.
Kiểm tra trên trình duyệt là để thuận tiện cho người dùng. Ai cũng có thể sửa trang hoặc gửi request mà không qua nó, nên máy chủ phải kiểm tra lại mọi giá trị.
Thông báo tùy chỉnh với setCustomValidity
Khi một quy tắc không viết được thành thuộc tính, chẳng hạn "hai mật khẩu phải trùng nhau", hãy đặt thông báo từ JavaScript. Trường có thông báo tùy chỉnh khác rỗng là không hợp lệ; chuỗi rỗng làm nó hợp lệ trở lại:
Trường nhập lại không có name, nên chỉ một bản mật khẩu được gửi đi.
Xử lý việc gửi form bằng JavaScript
Để gửi form mà không rời trang, hãy lắng nghe submit, gọi preventDefault() và đọc các trường bằng FormData. Lắng nghe submit thay vì click của nút sẽ bắt được mọi cách gửi form, kể cả Enter, và chỉ chạy sau khi phần kiểm tra có sẵn đã qua:
Object.fromEntries(new FormData(form)) biến các trường thành một object thông thường. Với những trường có thể có nhiều giá trị (các checkbox dùng chung tên, select cho chọn nhiều) hãy dùng formData.getAll('name'), vì object chỉ giữ giá trị cuối cùng.
Lỗi thường gặp
- Trường không có
name. Chúng bị bỏ khỏi dữ liệu gửi đi mà không có cảnh báo nào. - Dùng placeholder thay cho label. Gợi ý biến mất ngay khi người dùng bắt đầu gõ. Hãy dùng
<label>. - Một
<button>không cótypedùng cho việc khác ngoài gửi form. Bên trong form, nó là nút submit. - Form lồng trong form. Lồng form là không hợp lệ; trình duyệt bỏ qua thẻ
<form>bên trong. - Lắng nghe
clicktrên nút submit thay vìsubmittrên form. Cách gửi bằng phím Enter sẽ bị bỏ sót. - Tin vào kiểm tra của trình duyệt ở phía máy chủ. Hãy kiểm tra lại ở đó.
- Dùng GET cho mật khẩu. Mật khẩu sẽ nằm trong URL, lịch sử và log của máy chủ.
Câu hỏi thường gặp
Làm sao tạo form trong HTML?
Bọc các trường trong <form action="/signup" method="post">, đặt cho mỗi trường một name và một <label>, rồi kết thúc bằng <button type="submit">. Khi form được gửi, trình duyệt gửi từng cặp name=value tới URL trong action.
GET và POST trong form khác nhau thế nào?
method="get" (mặc định) đặt các trường vào URL, như /search?q=shoes, hợp với tìm kiếm và bộ lọc cần lưu dấu trang được. method="post" gửi chúng trong phần thân của request, là điều bạn cần cho đăng nhập, đăng ký và mọi thao tác làm thay đổi dữ liệu.
Vì sao một trường trong form không được gửi đi?
Trường đó không có thuộc tính name, hoặc đang bị disabled. Chỉ những trường có tên và không bị vô hiệu hóa mới được gửi. Checkbox hay radio button chưa được chọn cũng bị bỏ ra hoàn toàn.
fieldset và legend dùng để làm gì?
<fieldset> nhóm các trường liên quan và <legend> là tiêu đề của nhóm. Trình đọc màn hình đọc legend khi focus đi vào nhóm, nhờ vậy một nhóm radio button mới dễ hiểu, và disabled trên fieldset sẽ vô hiệu hóa mọi trường bên trong.
Làm sao kiểm tra form trong HTML mà không cần JavaScript?
Dùng thuộc tính: required, type="email", minlength, maxlength, min, max và pattern. Trình duyệt chặn việc gửi và hiện thông báo ở trường không hợp lệ đầu tiên. Luôn kiểm tra lại trên máy chủ, vì các bước kiểm tra này chạy trong trình duyệt của người dùng và có thể bị vượt qua.
Làm sao để form không tải lại trang?
Lắng nghe sự kiện submit của form và gọi event.preventDefault(), rồi tự gửi dữ liệu bằng fetch: form.addEventListener('submit', (e) => { e.preventDefault(); fetch(form.action, { method: 'POST', body: new FormData(form) }); }).