What is the best way to postpone the display of progress if the AJAX request finishes in fewer than X seconds

When I have multiple AJAX calls on a webpage, some complete quickly while others take longer depending on the action clicked.

I am looking to implement a "loader" that shows up after a certain number of seconds when AJAX is processing results.

I have managed to get the loader functioning:

   $(document).ajaxStart(function() {
        $("#loader").css("display","block");
    }).ajaxSuccess(function() {
        $("#loader").css("display","none");
    });

This works fine.

However, it flashes briefly on the screen when the AJAX request is fast, causing a distraction. While the functionality is great, I want to delay the loader's appearance for a few seconds so it doesn't flash unnecessarily.

I tried using setTimeout and jQuery queue to introduce a delay like this:

$(document).ajaxStart(function() {

    $("#loader").queue(function(){
        $(this).delay(5000);
        $(this).css("display","block");
        $(this).dequeue();
    });

}).ajaxSuccess(function() {
    $("#loader").css("display","none");
});

or:

$(document).ajaxStart(function() {

    setTimeout(function() { 
        $("#loader").css("display","block");
    }, 5000);

}).ajaxSuccess(function() {
    $("#loader").css("display","none");
});

(delaying jquery css changes)

or:

$(document).ajaxStart(function() {
    $("#loader").delay(5000).css("display","block")
}).ajaxSuccess(function() {
    $("#loader").css("display","none");
});

But the issue I encounter is that any attempt to delay the CSS change on ajax start often results in a delayed appearance... after the AJAX process has finished.

So what happens is that the page loads the AJAX data first and then 5 seconds later, the loader pops up.

Is there a way to instruct the ajaxStart() function to wait for X seconds before executing?

  • I prefer not to include this delay in the actual AJAX calls using something like onBefore function(), as some results are returned quickly and do not require a progress indicator. In most cases, the progress indicator should not be displayed. Typically, AJAX requests are completed within 5 seconds, with only a few taking longer (10-20 seconds).

  • I have included the removal of the 'loader' in the complete function() of the AJAX calls to ensure it disappears once the AJAX operation is done. However, this fails if the AJAX completes before the setTimeout() value is reached, resulting in the loader appearing afterwards when it shouldn't.

All I want is a CSS change on an element if the AJAX operation takes X seconds or more...is that achievable?

Is there a method to time something during AJAX requests?

Answer №1

setTimeout() has a useful functionality that allows you to cancel the timeout by referencing it, as explained in this resource.

var ajaxLoadTimeout;
$(document).ajaxStart(function() {
    ajaxLoadTimeout = setTimeout(function() { 
        $("#loader").css("display","block");
    }, 5000);

}).ajaxSuccess(function() {
    clearTimeout(ajaxLoadTimeout);
    $("#loader").css("display","none");
});

This approach ensures that the timeout is stopped before it triggers, rather than letting it run and do nothing if it's no longer needed (as mentioned in Jacob's response).

Answer №2

To ensure that the #loader is only shown after the ajax request has completed, you can implement the following logic:

let ajaxFinished; //declare a global variable to track if ajax request has finished
$(document).ajaxStart(function() {
    ajaxFinished = false; //set ajaxFinished to false each time an ajax request starts
    setTimeout(function() { 
        if(!ajaxFinished) $("#loader").css("display","block"); //show the loader if ajax request hasn't finished after 5 seconds
    }, 5000);

}).ajaxSuccess(function() {
    ajaxFinished = true; //mark ajax as finished when the request completes successfully
    $("#loader").css("display","none"); //hide the loader once ajax request is complete
});

Answer №3

Thanks to the great feedback I received, I was able to come up with a solution.

I specifically needed a localized "loading" image to display based on an element's ID. The global ajaxStart() and ajaxComplete() functions were not suitable for handling local events. Therefore, I opted for the beforeSend() function along with a timeout:

 $('.item').click( function (e) {
        e.preventDefault(); 
        var theID = $(this).attr('data');
        var theInfo = $('.holder#h' + theID);
        var loader = $('.waiting#w' + theID);
        $('.holder').slideUp(); //closes any open data holders
        var ajaxLoadTimeout;

        if (!$(theInfo).hasClass('opened')) {
            $(this).addClass('clicked');
            $(theInfo).addClass('opened');
            $(theInfo).html(''); //removes any existing data

        $.ajax({                                      
            url: '_core/inc/getdata.php',  
            type: 'POST',
            data: ({dataid: theID}),   
            dataType: 'html',

           // displays LOCAL loader before sending ajax request
           // but introduces a 3-millisecond delay
           // most ajax calls are completed within that time frame
           // mitigates the "flashing" of the loader for just a millisecond
            beforeSend : function() {
                ajaxLoadTimeout = setTimeout(function() { 
                $(loader).show();
                }, 300);

            },
            success: function(data) {
                $(theInfo).html(data);

                // Hides LOCAL loader upon successful ajax response
                clearTimeout(ajaxLoadTimeout);
                $(loader).hide();
            },
            complete: function(){
                    $(theinfo).slideDown();
                }
              });

              } else {
                $(this).removeClass('clicked');
                $(theInfo).removeClass('opened').slideUp();
            }
      });

Here is the relevant segment of PHP/HTML code:

echo '
<h1 class="item" data="'.$this_id.'">'.$this_title.' <span class="waiting" id="w'.$this_id.'"><i class="fa fa-refresh fa-spin fa-lg"></i></span></h1>

<section class="holder" id="h'.$this_id.'"></section>';

CSS: .waiting { discplay: none; }

Although there may be variations in opinions, this setup appears to be functioning correctly in my case.

It allows the font-awesome icon to be displayed alongside the item title when the loading process exceeds a few milliseconds.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The cookie generated through jQuery(view) cannot be retrieved in PHP(controller) on the initial try

I've encountered a strange issue with Chrome and Firefox, surprisingly it works fine on IE occasionally. [Edit1: Problem occurs intermittently with IE as well] Premise: On my homepageView.php, I utilize jQuery to create a cookie, which I'll re ...

What is the best way to halt a CSS transition using JavaScript when dealing with an image?

I am facing an issue while attempting to create a basic CSS transition using JavaScript. The goal is for the start button to trigger the movement of an element, based on the duration of the keyframe animation. Then, clicking the end button should make the ...

Leverage jQuery to retrieve information and fill in an HTML form

Seeking assistance with retrieving data based on a dropdown selection change. Specifically, choosing an Item ID from the dropdown and then populating textboxes and other dropdowns with values from the database. The other dropdowns already have assignment o ...

Exclude items from jQuery UI Sortable that do not fit the specified item selector

In a complex scenario, I have a table with two levels of groupings. The code I'm working with has a table structure with alternating rows labeled either "group" or "member" to display nested groups with their associated members. Below is an example o ...

Moving smoothly while retaining absolute positioning

I have a question about a particular scenario. I have a div element that is styled like a ball and I want it to transition diagonally across the page to the bottom right corner instead of moving suddenly. However, this is not happening as expected. Can you ...

Java webservice utilizing JSON technology, paired with a client programmed in JavaScript

I am just starting out in the world of web service development. I am currently working on an application using HTML5, JavaScript and jQuery, where I need to send data to a web service in JSON format. Here are my questions: 1) What is the best way to send ...

Troubleshooting: Why jQuery fails to function after inserting a new row into a table

In my project, I have created a table with a button that allows users to add rows dynamically. Each row consists of five columns and two dropdowns. The value selected in one dropdown affects the options available in the other dropdown. However, I am facing ...

Simulating a mobile device screen size using an embedded iframe

Imagine this scenario: What if instead of adjusting the browser window size to showcase a responsive web design, we could load the site into an IFRAME with the dimensions of a mobile screen. Could this concept actually work? Picture having an IFRAME like ...

Choose the nth item from a group of elements that do not have the same parent node in common

Is it possible to select a specific li element within a dynamic HTML structure without knowing the exact number of ul elements or li elements in each? From my understanding, neither :nth-child nor :nth-of-type can achieve this due to the elements needing ...

Click on the paint app to change colors using JavaScript

Trying to create a Paint feature in JS, here's the code snippet. I am looking to change the color of the trail from black to red by clicking on the "red" div, but I'm running out of ideas (without jQuery). let active = false; const draw = fu ...

Modify the appearance of each button based on the target value through the "Change Target Value" option

My task involves adjusting the background color of a button based on changes in the target value. Initially, I set the target value to "10". When I click my "1" button and decrease it to "9", the background color of the button changes to "red" because the ...

Using the AJAX post method to generate a JSON object from database results and send it back to a jQuery UI Dialog

I wrote a script that loads sample images from the database based on the relevant category when the page loads. Here's a simplified version of the PHP script: <?php $category = 'granite'; $samples = 'SELECT * FROM material WHERE ma ...

Alter the text upon hover, then revert back to the original text

I am working on a comment system where each comment includes a button that usually shows the number of replies it has. I am looking to create an effect where, when a user hovers over the button, the text changes from "3 replies" to "Reply!", and then rever ...

How can you match the width of a series of elements to the width of an image directly preceding the div?

Looking to ensure that a series of captions have the same width as the images preceding them. This is the HTML code: <div class="theparent"> <img src="pic.jpg"/> <div class="caption"> hello </div> <div> <div ...

How can we change a jQuery document click function to an inline onclick function?

Under certain circumstances, I have to refactor my click function into a standalone function and trigger it using inline onClick="myFunction();" This is my current code structure: $(document).on('click','.exBtn', function(){ var ex = ...

What is the method to utilize jQuery in validating the presence of the 'disabled' attribute within an <a> element?

In my HTML code, I have set a disabled='disabled' attribute on an <a> tag. How can I check if this attribute exists using jQuery? When I use the code below, it returns undefined. Even though I can see the disabled attribute in Firebug, all ...

Angular.js, Masonry, and the feature of sorting elements using jQueryUi are

I have been attempting to develop a straightforward Angular application that combines Masonry with a method for sorting my appended elements. Despite trying various examples using jQueryUi and a directive approach, I have not yet achieved the desired resul ...

Prevented a frame from "https://googleads.g.doubleclick.net" from accessing another frame

After placing ads on my website, they are displaying properly. However, I am receiving an error repeatedly in the console when the page loads: A frame from origin "" is being blocked from accessing a frame with origin "". The requesting frame has an "ht ...

Having trouble getting the toggleClass function to work properly?

I'm facing an issue with some straightforward code that I've written. $(function() { $("#tren").click(function() { $("#trens").toggleClass("show"); }); }); .show { color: "red"; } <ul> <li id="tren">Some text</li> < ...

Modifying the color of a specific node in jstree

I am attempting to modify the background color of the node I have selected in jstree. $('#syncrep').jstree({ 'core' : { 'data' : repository ...