Display loading indicator using AngularJS

AngularJS allows developers to extend HTML with new attributes called Directives. In simple terms, an AngularJS directive is essentially a function that executes when the Angular compiler finds it in the DOM (Document Object Model). Directives are extended HTML attributes with the prefix ng-. For instance, the ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

On the other hand, Services are substitutable objects that are wired together using dependency injection (DI). Developers can use services to organize and share code across your app. To use an Angular service, you add it as a dependency for the component (controller, service, filter or directive).

Through this post, we will learn how to display a simple loading indicator using AngularJS directives and services. The loading indicator thus implemented can be displayed while executing AJAX requests to remote web services.

Pre-requisites: Eclipse IDE for Java EE developers, Apache Tomcat 7.0

Step 1: Launch the Eclipse IDE and create a new Dynamic Web Project called AngularSpinnerDemo with target server runtime as Apache Tomcat 7.

create_dynamic_web_project

Now, let’s create our own directive that will display the spinner when the DOM is loaded.

Step 2: Create directive for Spinner

Create a new JavaScript file called spinner_directive.js that will include our custom directive. As the DOM (Document Object Model) is compiled by AngularJS, the directive controllers and link functions execute at different parts of the compile life-cycle.

spinner_directive.js

app.directive('spinner', function () {
    return {
        restrict: 'E',
        template: [
          '<span>',
          '  <img ng-show="showSpinner" ng-src="{{url}}" style="padding-right: 7px; width: {{ spinnerSize }}; vertical-align: middle" />',
          '  <span ng-show="loadingText && showSpinner">{{ loadingText }}</span>',
          '  <span ng-show="doneText && !showSpinner">{{ doneText }}</span>',
          '</span>'
        ].join(''),
        replace: true,
        scope: {
            id: '@',
            group: '@?',
            showSpinner: '@?',
            loadingText: '@?',
            doneText: '@?',
            onRegisterComplete: '&?',
            url: '@'
        },
        controller: function ($scope, $attrs, spinnerService) {
            // Register the spinner with the spinner service.
            spinnerService._register($scope);
            // Invoke the onRegisterComplete expression, if any.
            // Expose the spinner service for easy access.
            $scope.onRegisterComplete({ $spinnerService: spinnerService });
        },
        link: function (scope, elem, attrs) {
            // Check for pre-defined size aliases and set pixel width accordingly.
            if (attrs.hasOwnProperty('size')) {
                attrs.size = attrs.size.toLowerCase();
            }
            switch (attrs.size) {
                case 'tiny':
                    scope.spinnerSize = '15px';
                    break;
                case 'small':
                    scope.spinnerSize = '25px';
                    break;
                case 'medium':
                    scope.spinnerSize = '35px';
                    break;
                case 'large':
                    scope.spinnerSize = '75px';
                    break;
                default:
                    scope.spinnerSize = '50px';
                    break;
            }
        }
    };
});

Step 3: Create service for Spinner

Create a new JavaScript file called spinner_service.js that will include the definition of our spinner service as follows!

spinner_service.js

app.factory('spinnerService', function () {
    var cache = {};
    return {

        // A private function intended for spinner directives to register themselves with the service.
        _register: function (spinnerScope) {
            // If no id is passed in, throw an exception.
            if (!spinnerScope.id) {
                throw new Error("A spinner must have an ID to register with the spinner service.");
            }

            // Add our spinner directive's scope to the cache.
            cache[spinnerScope.id] = spinnerScope;
        },

        // A private function exposed just in case the user really needs to manually unregister a spinner.
        _unregister: function (spinnerId) {
            delete cache[spinnerId];
        },

        // A private function that will remove an entire spinner group if needed.
        _unregisterGroup: function (group) {
            for (var spinnerId in cache) {
                if (cache.hasOwnProperty(spinnerId)) {
                    if (cache[spinnerId].group === group) {
                        delete cache[spinnerId];
                    }
                }
            }
        },

        // A private function that will clear out all spinners from the cache.
        _unregisterAll: function () {
            for (var spinnerId in cache) {
                if (cache.hasOwnProperty(pinnerId)) {
                    delete cache[spinnerId];
                }
            }
        },

        // Show the specified spinner.
        // If loadingText is specified, replace the loadingText specified on the directive as we show the spinner.
        show: function (spinnerId, loadingText) {

            $("body").find("#loading").addClass("mydiv");
            if (cache.hasOwnProperty(spinnerId)) {
                var spinnerScope = cache[spinnerId];
                spinnerScope.showSpinner = true;
                if (loadingText !== undefined) {
                    spinnerScope.loadingText = loadingText;
                }

            }
        },

        // Hide the specified spinner.
        // If doneText is specified, replace the doneText specified on the directive as we hide the spinner.
        hide: function (spinnerId, doneText) {

            if (cache.hasOwnProperty(spinnerId)) {
                var spinnerScope = cache[spinnerId];
                $("body").find("#loading").removeClass("mydiv");
                spinnerScope.showSpinner = false;

                if (doneText !== undefined) {
                    spinnerScope.doneText = doneText;
                }

            }
        }

    };
});

Step 4: Create controller

spinnercntrl.js

app.controller("spinnercntrl", function ($scope,spinnerService) {

	//initially hide the spinner
	spinnerService.hide('mySpinner');

	/*method called on click of show spinner button*/
	$scope.showSpinner = function(){
		
		spinnerService.show('mySpinner');
		
		//hide the spinner after 3 seconds
		setTimeout(function(){ 
			spinnerService.hide('mySpinner');
		}, 3000);

	};

});

Finally, run the application on the Tomcat server. If no errors occur, then you should see the loading indicator on click of the Show spinner button.

output_1

output_2

Source code for this tutorial can be found over here.

Reference: AngularJS Developer Guide

Karan Balkar About Karan Balkar
self proclaimed extraterrestrial fandroid, computer engineer, amateur gamer and die hard punk rock fan!

Leave a Reply

Your email address will not be published. Required fields are marked *