user3378165
user3378165

Reputation: 6896

How to add preloader to website without manually show/hide it

On my website (MVC and web API) I have added a preloader for a better user experience purpose.

I have added the preloader at two points:

  1. After Login, between the user is authenticated and the redirection to the homepage.
  2. In every page that loads data from the server.

I did it with an image that I show when the page/data loads and I hide when the data is fully loaded.

<div id="dvReqSpinner" style="display: none;">
  <br />
  <center><img src="~/images/loading_spinner.gif" /></center>
  <br />
</div>

And with jquery I show and hide it:

$("#dvReqSpinner").show();
$("#dvReqSpinner").hide();

It's a little bit anoying to keep showing and hiding an image every time I need to load data (using an AJAX call to web API, authenticating the user etc.. - Every action that takes time and I want to show the user that something is "happening"), isn't there any "automatic" option to have a preloader on a website?

Upvotes: 0

Views: 1057

Answers (3)

Pedro Silva
Pedro Silva

Reputation: 470

I don't know if its the case, but if you use jquery ajax to handle your requests, you can do something like this:

$(document).ajaxStart(function() {
   // every time a request starts
   $("#dvReqSpinner").show();

}).ajaxStop(function() {
   // every time a request ends
   $("#dvReqSpinner").hide();

});

EDIT: If you want to avoid showing the spinner for fast requests, i think this can make it work:

var delayms = 3000; // 3 seconds

var spinnerTimeOut = null;

$(document).ajaxStart(function() {
   // for every request, wait for {delayms}, then show spinner

   if(spinnerTimeOut!=null){
      clearTimeout(spinnerTimeOut);
   }

   spinnerTimeOut = setTimeout(function(){  
      $("#dvReqSpinner").show();
   }, delayms);

}).ajaxStop(function() {
   // every time a request ends
   clearTimeout(spinnerTimeOut); // cancel timeout execution
   $("#dvReqSpinner").hide();


});

Give it a try. i couldn't test it -.-'

Upvotes: 2

Umamaheswaran
Umamaheswaran

Reputation: 3878

You can use global ajax handlers for this.

This code will execute whenever you make an ajax request. all you have to do here is enable your spinner.

$( document ).ajaxSend(function() {
  $("#dvReqSpinner").show();
});

This code will execute once your ajax request succeeded. all you have to do here is enable your spinner.

$( document ).ajaxSuccess(function( event, request, settings ) {
   $("#dvReqSpinner").hide();
});

You can also use other global ajax function to handle things like showing a popup when a ajax request fails using ".ajaxError()"

Below link will have details of all the other functions

https://api.jquery.com/category/ajax/global-ajax-event-handlers/

Upvotes: 0

Tomalak
Tomalak

Reputation: 338228

To show or hide a loading indicator in a single page app, I would add and remove a CSS class from the body:

#dvReqSpinner {
    display: none;
}

body.loading #dvReqSpinner {
    display: block;
}

and

$("body").addClass("loading");
$("body").removeClass("loading");

Primarily this would make the JS code independent on the actual page layout, so it's "nicer" but not really "less work".

To do it "automatically", I recommend abstracting your Ajax layer into a helper object:

var API = {
    runningCalls: 0,
    // basic function that is responsible for all Ajax calls and housekeeping
    ajax: function (options) {
        var self = this;

        self.runningCalls++;
        $("body").addClass("loading");

        return $.ajax(options).always(function () {
            self.runningCalls--;
            if (self.runningCalls === 0) $("body").removeClass("loading");
        }).fail(function (jqXhr, status, error) {
            console.log(error);
        });
    },
    // generic GET to be used by more specialized functions
    get: function (url, params) {
        return this.ajax({
            method: 'GET',
            url: url,
            data: params
        });
    },
    // generic POST to be used by more specialized functions
    post: function (url, params) {
        return this.ajax({
            method: 'POST',
            url: url,
            data: params
        });
    },
    // generic POST JSON to be used by more specialized functions
    postJson: function (url, params) {
        return this.ajax({
            method: 'POST',
            url: url,
            data: JSON.stringify(params),
            dataType: 'json'
        });
    },
    // specialized function to return That Thing with a certain ID
    getThatThing: function (id) {
        return this.get("/api/thatThing", {id: id});
    }
    // and so on ...
};

so that later, in your application code, you can call it very simply like this:

API.getThatThing(5).done(function (result) {
    // show result on your page
});

and be sure that the low-level stuff like showing the spinner has been taken care of.

Upvotes: 2

Related Questions