Search code examples
javascriptjqueryajaxxmlhttprequestfetch-api

AJAX call failing to process form


I have an email sign-up form on a website.

The form appears in two areas of each web page: the header and the footer

It's the same exact form, just available on the top and bottom of the page for better UX and accessibility.

The form uses a jQuery/AJAX script to provide success and error responses to the user. (i.e., "Success! Your subscription is complete." and "Error. Please review and re-submit")

The problem I'm having is that the header form processes but the footer form does not.

Any ideas what's wrong with this code? Thanks.

P.S. The form was working perfectly when the header and footer forms each had their own script. The problem started when the scripts were consolidated into one file. I've posted the original scripts at the bottom. Also, nothing has been changed in the PHP, so I don't think the problem is there.

$(function() {

  // get the forms
  var form = $('#header-form, #footer-form');

  // set up event listener
  $(form).submit(function(e) {
    // disable html submit button
    e.preventDefault();

    // get the submit button
    var submitButton = $('[type=submit]', this);

    // get the messages element
    var formResponses = $('#header-form-responses, #footer-form-responses', this);
    formResponses.text(" ");

    // serialize form data
    var formData = $(form).serialize();

    // disable submit button to prevent unnecessary submission
    submitButton.attr('disabled', 'disabled');

    // tell users that form is sending
    submitButton.text('Processing...');

    // submit form via AJAX
    $.ajax({
        type: 'POST',
        url: $(form).attr('action'),
        data: formData
      })

      .done(function(response) {
        // make sure formResponses element has 'success' class
        $(formResponses).removeClass('error');
        $(formResponses).addClass('success');

        // set message text
        $(formResponses).text('Your subscription is complete. Thank you!');

        // clear form
        $('input').val('');
      })

      .fail(function(data) {
        // make sure formResponses element has 'error' class
        $(formResponses).removeClass('success');
        $(formResponses).addClass('error');

        // set the message text
        $(formResponses).text('Input error. Please review and re-submit.');
      })

      .always(function(data) { // this will always fire even if the request fails
        submitButton.removeAttr('disabled');
        submitButton.text('Send');
      });

  });

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- simplified HTML -->

<form action="form_processing.php" method="post" id="header-form">
  <input type="email" name="email_subscription">
  <button type="submit" id="header-form-submit">Submit</button>
  <div id="header-form-responses"></div>
</form>

<form action="form_processing.php" method="post" id="footer-form">
  <input type="email" name="email_subscription">
  <button type="submit" id="footer-form-submit">Submit</button>
  <div id="footer-form-responses"></div>
</form>

Here's the original header code (works perfectly):

$(function() {

  var form = $('#header-form');

  var formResponses = $('#header-form-responses');

  var submitButton = $("#header-form-submit");

  $(form).submit(function(e) {
    e.preventDefault();

    var formData = $(form).serialize();

    submitButton.attr('disabled', 'disabled');

    submitButton.text('Processing...');

    $.ajax({
        type: 'POST',
        url: $(form).attr('action'),
        data: formData
      })
      .done(function(response) {
        $(formResponses).removeClass('error');
        $(formResponses).addClass('success');

        $(formResponses).text('Your subscription is complete. Thank you!');

        $('input').val('');
      })
      .fail(function(data) {
        $(formResponses).removeClass('success');
        $(formResponses).addClass('error');

        $(formResponses).text('Input error. Please review and re-submit.');
      }).always(function(data) {
        submitButton.removeAttr('disabled');
        submitButton.text('Send');
      });

  });

});

Here's the original footer code (works perfectly):

$(function() {

  var form = $('#footer-form');

  var formResponses = $('#footer-form-responses');

  var submitButton = $("#footer-form-submit");

  $(form).submit(function(e) {
    e.preventDefault();

    var formData = $(form).serialize();

    submitButton.attr('disabled', 'disabled');

    submitButton.text('Processing...');

    $.ajax({
        type: 'POST',
        url: $(form).attr('action'),
        data: formData
      })
      .done(function(response) {
        $(formResponses).removeClass('error');
        $(formResponses).addClass('success');

        $(formResponses).text('Subscription complete.');

        $('input').val('');
      })

      .fail(function(data) {
        $(formResponses).removeClass('success');
        $(formResponses).addClass('error');

        $(formResponses).text('Input error. Please review and re-submit.');
      }).always(function(data) {
        submitButton.removeAttr('disabled');
        submitButton.text('Send');
      });

  });

});


Solution

  • Within the $(form).submit( you're still using $(form), eg

    var formData = $(form).serialize();
    

    as form = $('#header-form, #footer-form') any call to $(form) (or just form) will affect/apply to/read from both forms. This depends on what the call is, eg form.attr("action") will always get the action from the first form.

    Within the handler, change all $(form) (or just form) to $(this):

    var formData = $(this).serialize();
    ...
    url: $(this).attr('action'),
    

    be careful using this inside a callback, so if you do need the relevant form then instead, change to

    $('#header-form, #footer-form').submit(function(e) {
      var form = $(this);
    

    and continue to use form.


    Note that in your code form is already a jquery object, but jquery allows you to "double wrap" - ie $(form) is the same as $($(form))


    I recommend you remove the outer form variable completely, ie change to

    // set up event listener
    $('#header-form, #footer-form').submit(function(e) {
    

    which will help to remove the issue of using form not meaning this form.