How to display wait message in AngularJS while data loading?

All we need is an easy explanation of the problem, so here it is.

I’m new in AngularJS and trying to find the way how to display wait message while data loading? I mean data starts loading, display message and remove it when data loading is done.

I’ve searched the internet but haven’t found anything I need…

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

<div ng-if="data.dataLoading">
    Loading...
</div>

JS

$scope.data.dataLoading = true;

return someService.getData().then(function (results) {                    
    ...
}).finally(function () {
    $scope.data.dataLoading = false;
});

Method 2

Depends from where you’re loading the data. One solution I used was to create a LoadingService

app.factory('LoadingService', function($rootScope) {
    return {
        loading : function(message) {
             $rootScope.loadingMessage = message;
        },
        loaded : function() {
             $rootScope.loadingMessage = null;
        }
    }
}).controller('FooController', function($scope,$http,LoadingService) {

   $scope.loadSomeData = function() {
       LoadingService.loading('Data is loading');

       $http.get('/data').finally(function() {
            LoadingService.loaded();
       });
   };
});

Since I had only one place where the message was being displayed I could use RootScope to handle this. If you want to have a loading message multiple times you could write a directive also to handle this like Codezilla posted

Method 3

Edit: does not work on version 1.3.0 . Use request/response interceptors.

If you want to listen to all requests globally and display a loading widget whenever there’s a request pending, you can count the requests using request/response transformers. You simply add a counter and increase on a new request and decrease it on response. I use a provider for that:

$httpProvider
  .defaults
  .transformRequest
  .push(function(data) {
      requestNotificationProvider
      .fireRequestStarted(data);
      return data;
});

And the same for transformResponse. Then the same provider holds the information on how many requests are pending and you can use them in a directive. You can read (& copy/paste the code) a full blog post on that here:
http://www.kvetis.com/2014/01/angularjs-loading-widget.html There’s a working demo in attached.

Method 4

I’ve answered this question in this StackOverflow article, but here’s a recap of what I did.

If you style your code correctly, and make sure all calls to a web service pass through one particular factory function, then you can make that factory function handle showing and hiding your “Please Wait” popup.

Here’s the factory function which I use to call all of my GET web services:

myApp.factory('httpGetFactory', function ($http, $q) {
    return function (scope, URL) {
        //  This Factory method calls a GET web service, and displays a modal error message if something goes wrong.
        scope.$broadcast('app-start-loading');          //  Show the "Please wait" popup

        return $http({
            url: URL,
            method: "GET",
            headers: { 'Content-Type': undefined }
        }).then(function (response) {
            scope.$broadcast('app-finish-loading');     //  Hide the "Please wait" popup
            if (typeof response.data === 'object') {
                return response.data;
            } else {
                // invalid response
                return $q.reject(response.data);
            }
        }, function (errorResponse) {
            scope.$broadcast('app-finish-loading');     //  Hide the "Please wait" popup

            //  The WCF Web Service returned an error.  
            //  Let's display the HTTP Status Code, and any statusText which it returned.
            var HTTPErrorNumber = (errorResponse.status == 500) ? "" : "HTTP status code: " + errorResponse.status + "\r\n";
            var HTTPErrorStatusText = errorResponse.statusText;

            var message = HTTPErrorNumber + HTTPErrorStatusText;

            BootstrapDialog.show({
                title: 'Error',
                message: message,
                buttons: [{
                    label: 'OK',
                    action: function (dialog) {
                        dialog.close();
                    },
                    draggable: true
                }]
            });

            return $q.reject(errorResponse.data);
        });
    };
});

This would get called like this:

myApp.webServicesURL = "http://localhost:15021/Service1.svc";

var dsLoadAllEmployees = function (scope)
{
     //  Load all survey records, from our web server
     $scope.LoadingMessage = "Loading Employees data...";

     var URL = myApp.webServicesURL + "/loadAllEmployees";
     return httpGetFactory(scope, URL);
}

Here’s the “Please wait” control which I use on each page..

<please-wait message="{{LoadingMessage}}" ></please-wait>

… and its code looks like this…

myApp.directive('pleaseWait',  
    function ($parse) {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                message: '@message'
            },
            link: function (scope, element, attrs) {
                scope.$on('app-start-loading', function () {
                    element.fadeIn(); 
                });
                scope.$on('app-finish-loading', function(){
                    element.animate({
                        top: "+=15px",
                        opacity: "0"
                    }, 500);
                });
            },
            template: '<div class="cssPleaseWait"><span>{{ message }}</span></div>'
        }
    });

Using this structure, any of my Angular controllers can load data from a web service in just a few lines, and leave the factory to look after showing/hiding the “Please wait” message and to display any errors which occur:

   $scope.LoadAllSurveys = function () {
        DataService.dsLoadAllSurveys($scope).then(function (response) {
            //  Success
            $scope.listOfSurveys = response.GetAllSurveysResult;
        });
   }

Nice, hey ?

Method 5

I dont know if is the correct way, but I put on my template

 <img id="spinner" ng-src="images/spinner.gif" ng-if="!data" >
 <div ng-repeat="repo in repos | orderBy: repoSortOrder">...</div>

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply