Submitting a form using AJAX

To submit a form using AJAX - pass the serialized form data as the payload when posting to any front-end URL.

WARNING

This solution currently will not work with multi-page forms.

Return values

The AJAX request must be a post request and it will return a JSON object with the following values:

On successful single-page form post

  • success - A boolean value of true
  • finished - A boolean value of true
  • returnUrl - The return URL specified for the form
  • submissionId - An int value of the submission ID if one was generated

On form error

  • success - A boolean value of false
  • finished - A boolean value of false
  • errors - An object of field handles as keys and each containing an array of error messages.
    • An example, if the form's firstName and lastName fields were required, but not filled out, the returning object would be:
"errors": {
	"firstName": ["This field is required"],
	"lastName": ["This field is required"]
}
1
2
3
4

Usage in Templates

Here's a fully working Bootstrap form AJAX example:

<script>
  var form = document.getElementById('my-form');
  form.addEventListener('submit', function (event) {
    let data = new FormData(form);
    let request = new XMLHttpRequest();

    // Safari hack - remove empty file upload inputs
    // Otherwise an ajax call with empty file uploads causes immense lag
    if (navigator.userAgent.indexOf("Safari") > -1) {
      for (let i = 0; i < form.elements.length; i++) {
        if (form.elements[i].type === "file") {
          if (form.elements[i].value === "") {
            var elem = form.elements[i];
            data.delete(elem.name);
          }
        }
      }
    }

    var method = form.getAttribute("method");
    var action = form.getAttribute("action");

    request.open(method, action ? action : window.location.href, true);
    request.setRequestHeader("Cache-Control", "no-cache");

    // Set the AJAX headers
    request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    request.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest");

    request.onload = () => {
      if (request.status === 200) {
        var response = JSON.parse(request.response);
        var success = response.success;
        var finished = response.finished;
        var actions = response.actions ? response.actions : [];
        var errors = response.errors;
        var formErrors = response.formErrors;
        var honeypot = response.honeypot;

        if (!actions.length) {
          if (success && finished) {
            // Reset the form so that the user may enter fresh information
            form.reset();

            // ==================================
            // Perform something after the
            // form saves successfully
            // ==================================

          } else if (errors || formErrors) {

            // ==================================
            // Do something with the errors here
            // ==================================

            console.error(errors, formErrors);
          }
        }

        // ==================================
        // Honeypot update logic
        // ==================================
        if (honeypot) {
          var honeypotInput = form.querySelector("input[name^=freeform_form_handle]");
          if (honeypotInput) {
            honeypotInput.setAttribute("name", honeypot.name);
            honeypotInput.setAttribute("id", honeypot.name);
            honeypotInput.value = honeypot.hash;
          }
        }
      } else {
        console.error(request);
      }
    };

    request.send(data);

    event.stopPropagation();
    event.preventDefault();
    return false;
  });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Last Updated: 8/4/2020, 2:35:05 AM