Submit HTML Form không tải lại trang với AJAX

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.

Single Page Application – Mọi tương tác giữa client và server chủ yếu là trao đổi dữ liệu

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$.post, trong đó hai cái sau là wrapper của cái đầu tiên dành riêng cho GET và POST method.

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 goes here
            // ..
        }).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ỗi Boundary 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.