0

I have an ajax function and thought it would be nice to include a little ajax-spinner to tell the enduser something is actually happening. This is my current jQuery function:

$('#contact-form').submit(function(e)
{
    e.preventDefault();

    let overlay = $('#overlay'),
        loader = $('#loader-popup');

    console.log(overlay);
    console.log(loader);

    console.log('===================');

    //show overlay
    overlay.removeClass('hidden');
    loader.removeClass('hidden');

    console.log(overlay);
    console.log(loader);

    let formData = new FormData($(this)[0]),
        params = [];

    $.ajax({
        data: formData,
        type: 'post',
        url: '/pages/contact-us/action/send.php',
        cache: false,
        contentType: false,
        processData: false,
        success: function(res)
        {
            if (res == 1) {
                params['type'] = 1;
                params['msg'] = 'We will be with you as soon as we can!'
            } else {
                try {
                    res = $.parseJSON(res);
                    let data = [];

                    $.each(res, function(key, value) {data.push(value)});

                    params['type'] = 2;
                    params['msg'] = data.join('<br />')
                } catch(e) {
                    console.log(e);
                    alert('Huh. that\'s weird, something went wrong! Please try again');

                    //cause syntax error to stop script working
                    die()
                }
            }

            validator.displayAlert(params['type'], params['msg'])
        },
        error: function(res)
        {
            console.log(res);
            alert('Don\'t worry.. it\'s not you, it\'s us.')
        }
    });

    //hide overlay
    overlay.addClass('hidden');
    loader.addClass('hidden');
});

But weirdly the overlay doesn't show, nor does the loader. What makes this hard to kinda debug and fathom is the console.log output.

first console.log(overlay)
Object [ div#overlay.hidden ]

second console.log(loader)
Object [ div#loader-popup.hidden ]

third console.log(overlay)
Object [ div#overlay ]

fourth console.log(loader)
Object [ div#loader-popup ]

So I can see that my .removeClass() function is working, however, inspecting my page once the form is being submitted shows the elements with the hidden class. If I manually remove that hidden class in the inspector tab then everything shows, so I know it's not a CSS issue.

You can see this happen on a much simpler scale here

I've also tried with .toggle() with no avail.

How do I even begin to debug something that seems to work behind-the-scenes but, not on screen?

treyBake
  • 6,440
  • 6
  • 26
  • 57
  • 4
    You have the `overlay.addClass('hidden');` line outside the async ajax call? Surely this should be inside else it will be called straight away? Perhaps inside the success callback? – Christheoreo Jul 15 '19 at 10:19

2 Answers2

2

You should call hide the overlay in your callback, because it'll be executing asynchronously.

Something like

try {
    res = $.parseJSON(res);
    let data = [];

    $.each(res, function(key, value) {
        data.push(value)
    });

    params['type'] = 2;
    params['msg'] = data.join('<br />')
} catch (e) {
    console.log(e);
    alert('Huh. that\'s weird, something went wrong! Please try again');

    //cause syntax error to stop script working
    die()
} finally {
    //hide overlay


    overlay.addClass('hidden');
    loader.addClass('hidden');
}
Craig Harley
  • 304
  • 5
  • 18
0

The logic within the $.ajax() call is asynchronous. As such you remove the class then immediately add it back in as the AJAX request is in progress.

To fix this, change the addClass() calls to be made after the AJAX request completes. In your case the best place to do this would be in the complete callback as it will fire whether the AJAX request completed successfully or with an error:

$('#contact-form').submit(function(e) {
  e.preventDefault();

  let $overlays = $('#overlay, #loader-popup').removeClass('hidden');
  let formData = new FormData(this),
    params = [];

  $.ajax({
    // ajax settings...
    complete: function() {
      $overlays.addClass('hidden');
    }
  });
});
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • ah.. bout to rm question, should be closed as can't be reproduced.. plus probs a dupe out there about async usage that would apply here.. sorry! – treyBake Jul 15 '19 at 10:23
  • No problem. Also note that you can just use `this` in the FormData call. Right now you're using a Element object to create a jQuery object just to get the Element back out of it again. – Rory McCrossan Jul 15 '19 at 10:25
  • Ah didn't know that! Thought as I was in a jQuery obj, `this` might not equal `$(this)` but that's cool, thank you ^.^ – treyBake Jul 15 '19 at 10:30