Bài viết này hướng dẫn cách submit form mà không tải lại trang tạo ra trải nghiệm liền mạch, đặc biệt là với các Web App.
Tại sao nên thiết kế form submit không cần tải lại trang
Xu hướng thiết kế website hiện nay là tạo ra trải nghiệm liền mạch, không có độ trễ, đặc biệt là với các Web App mong muốn đem lại trải nghiệm như Native App trên Smart phone. Phong cách website kiểu này gọi là Single Page Application.
Với thiết kế này, Server chỉ thực hiện nhiệm vụ xử lý và trao đổi dữ liệu với Client qua REST API. Việc render giao diện sẽ nằm ở Client với HTML5, CSS3 và các framework JavaScript như AngularJS hay Vue.JS v.v… Như vậy là cũng giảm tải chút chút cho Server.
Giải pháp trao đổi dữ liệu không tải lại trang ở đây là sử dụng AJAX để thực hiện request và nhận lại dữ liệu dưới dạng một data format nào đó dễ dàng xử lý bằng JavaScript, ví du JSON hoặc XML.
Cách dùng jQuery.ajax để submit form không tải lại trang
JQuery cung cấp 3 hàm cho phép chúng ta thực hiện AJAX request đó là $.ajax
, $.get
và $.post
, trong đó $.get
và $.post
chính là wrapper của $.ajax
dành riêng cho GET và POST method vì vậy tôi sẽ không dùng chúng.
Dưới đây là một ví dụ sử dụng $.ajax()
để submit form mà không cần reload. Giả sử ta có một form như sau:
<form action="register.php" method="POST"> <input name="username" type="text"> <input name="password" type="password"> <input value="Submit" type="submit"> </form>
Đoạn mã JavaScript sau sử dụng $.ajax
của thư viện jQuery để submit form này.
$(document).ready(function() { $('form').submit(function(event) { $.ajax({ method: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize(), /* ... other AJAX settings ... */ }).done(function(response) { // Process the response here }); event.preventDefault(); // <- avoid reloading }); });
Lưu ý, để ngăn tải lại trang, ta phải gọi event.preventDefault()
hoặc đơn giản là return false
trong callback của $.submit()
.
Ở đây ta sử dụng hàm $.serialize
để tách dữ liệu từ form thành Query String, phù hợp với ContentType mặc định là application/x-www-form-urlencoded; charset=UTF-8
.
Nếu form của chúng ta gửi có cấu trúc dữ liệu phức tạp thì hãy tham khảo giải pháp tạo HTML Form chứa object và array.
Upload file với jQuery.ajax và FormData
Để upload được file với AJAX, ta cần sự hỗ trợ của đối tượng FormData. Về cơ bản đối tượng FormData cho phép ta gửi dữ liệu kiểu key/value thông qua giao diện XMLHttpRequest
giống như khi submit()
.
Ví dụ với form như sau có các trường thông tin thông thường và kèm với cả một trường lựa chọn file. Lưu ý định dạng encoding type cho form có file upload là multipart/form-data
.
<form action="upload.php" method="POST" enctype="multipart/form-data"> <input name="name" type="text"> <input name="email" type="email"> <input name="file" type="file"> <input value="Submit" type="submit"> </form>
Phần xử lý form có chút thay đổi đó là thay vì dùng $.serialize()
thì ta sử dụng FormData
như sau:
$(document).ready(function() { $('form').submit(function(event) { $.ajax({ method: $(this).attr('method'), url: $(this).attr('action'), enctype: $(this).attr('enctype'), data: new FormData(this), cache: false, // do not cache this request contentType: false, // prevent missing boundary string processData: false, // do not transform to query string timeout: 60000, xhr: function () { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { xhr.upload.addEventListener('progress', progressHandler, false); } return xhr; }, }).done(function(response) { // Process the response here }); event.preventDefault(); }); // Handle file upload progress function progressHandler(event) { var percent = 0; var position = event.loaded || event.position; var total = event.total; if (event.lengthComputable) { percent = Math.ceil(position / total * 100); } // display the progress console.log('Uploading ', percent + '%'); } });
Lưu ý thêm là ta cần bổ sung cấu hình sau cho $.ajax()
nếu không request sẽ bị lỗi:
cache: false
– Ngăn trình duyệt không cache request này.contentType: false
– Không cho jQuery gửi Content Type, nếu không sẽ làm mất chuỗiBoundary
trong request.processData: false
– Không cho jQuery tự động xử lý data thành query string.
P/S: Hàm xử lý trên có bonus thêm một phần xử lý upload progress là progressHandler
. Hãy thay đổi nội dung theo ý của bạn.