Waiting indicator using AngularJS interceptors

There are a number of needs that routinely come up when putting together a web UI.   This indicator notifies the user that action is occurring in the background, and goes away automatically when everything is done.
please wait
This happens automatically when your AngularJS app is requesting information via http. This is similar to other code on the web, but is modified it to suit the following needs:

  • Displays wait indicator automatically when http requests are initiated.
  • Tracks the number of requests, and dismisses the indicator when all are resolved.
  • A delay of one second prevents indicator from displaying during angular loading views and quick requests.
  • No jquery (yay)

Here it is on JSFiddle

If you’re looking for code (and you probably are), I recommend taking a look at the JSFiddle link above – it integrates the code, css and html.

We’re using several key AngularJS features here:

Directive

The directive is Angular’s way to hook UI elements to javascript functionality. Much of the logic is located here.

myApp.directive("loadingIndicator", function (loadingCounts, $timeout) {
    return {
        restrict: "A",
        link: function (scope, element, attrs) {
            scope.$on("loading-started", function (e) {
                loadingCounts.enable_count++;
                console.log("displaying indicator " + loadingCounts.enable_count);
                //only show if longer than one sencond
                $timeout(function () {
                    if (loadingCounts.enable_count > loadingCounts.disable_count) {
                        element.css({ "display": "" });
                    }
                }, 1000);
            });
            scope.$on("loading-complete", function (e) {
                loadingCounts.disable_count++;
                console.log("hiding indicator " + loadingCounts.disable_count);
                if (loadingCounts.enable_count == loadingCounts.disable_count) {
                    element.css({ "display": "none" });
                }
            });
        }
    };
});

Interceptors

Allows us to tie into http-related events and run our code at that time. In this case we are hooking into both the request, response and responseError (just in case). Here’s another post on interceptors.

myApp.config(function ($httpProvider) {
    $httpProvider.interceptors.push(function ($q, $rootScope) {
        return {
            'request': function (config) {
                $rootScope.$broadcast('loading-started');
                return config || $q.when(config);
            },
            'response': function (response) {
                $rootScope.$broadcast('loading-complete');
                return response || $q.when(response);
            },
            'responseError': function (rejection) {
                $rootScope.$broadcast('loading-complete');
                return $q.reject(rejection);
            }
        };
    });
});

Broadcast

Broadcast is the way we can fire (and respond to) our own events. As you can see, the interceptor events use $broadcast messages to trigger the logic (located in the directive) to show or hide the indicator.

You can implement this solution from the code on this page, if you include the following:

myApp.factory('loadingCounts', function () {
    return {
        enable_count: 0,
        disable_count: 0
    }
});

See it in action: Here it is on JSFiddle

3 comments

  1. Pingback: 07.07.2015 | gvr4wd