1

I have a loading icon set up on my page that looks like this:

<div class="loading-mask" 
    data-ng-show="action != null">
    <span>{{action}} ...</span>
</div>

When I set $scope.action to a message appears in the loading box.

When loading my page I have a number of different async processes that get data. For example I have:

   getUserProfiles: function ($scope) {
        var url = '/api/UserProfile/GetSelect';
        $http({ method: 'GET', url: url })
            .success(function (data, status, headers, config) {
                $scope.option.userProfiles = data;
            })
            .error(function (data, status, headers, config) {
                alert("Error: No data returned from " + url);
            });
    },

and:

    getSubjects: function ($scope) {
        var url = '/api/Subject/GetSelect';
        $http({ method: 'GET', url: url })
            .success(function (data, status, headers, config) {
                $scope.option.subjects = data;
            })
            .error(function (data, status, headers, config) {
                alert("Error: No data returned from " + url);
            });
    },

How can I make it so that the first of these async processes causes a "Loading" message to appear and the last of the async process causes the loading box to not show any more. Note at this time I am not concerned about error messages. I just want the loading to not show when everything is completed.

Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427

2 Answers2

2

To expand on what devmiles has said, but to handle the multiple asynchronous functions, you will want to set a loading flag on your first function to be called. I.e.:

   getUserProfiles: function ($scope) {
    $scope.loading = true;
    var url = '/api/UserProfile/GetSelect';
    $http({ method: 'GET', url: url })
        .success(function (data, status, headers, config) {
            $scope.option.userProfiles = data;
        })
        .error(function (data, status, headers, config) {
            alert("Error: No data returned from " + url);
        });
},

And then you will want to wrap each of your asynchronous functions in a promise, like so:

   getUserProfiles: function ($scope) {
    var deferred = $q.defer();
    $scope.loading = true;
    var url = '/api/UserProfile/GetSelect';
    $http({ method: 'GET', url: url })
        .success(function (data, status, headers, config) {
            $scope.option.userProfiles = data;
            deferred.resolve();
        })
        .error(function (data, status, headers, config) {
            alert("Error: No data returned from " + url);
            deferred.reject();
        });
   return deferred;
},

You can then call $q.all on all of your asynchronous functions, and the success callback of this will occur once all asynchronous functions have resolved:

$q.all([getUserProfiles, getSubjects]).then(function() {
    $scope.loading = false;
}

This means once all of your functions have resolved, loading will be set to false.

NB: If you want to access the data of your callbacks, you can pass it in as a parameter of "deferred.resolve(x)", and then in your $q.all callback, it will be available as function(x) { do something with x }.

Hope this helps!

EDIT: Don't forget to pass in angular's promise service, $q, to the controller where your functions are.

B Cotter
  • 951
  • 5
  • 7
  • http://stackoverflow.com/users/2515902/b-cotter I like this answer but how will I know when to call $q.all ? – Samantha J T Star Oct 15 '13 at 16:47
  • You don't explicitly call it, you just declare it. By that I mean you're saying 'when all of these things have happened, do 'this', where 'this' is what you put in .then(function () { xxxx} ). So you don't have to worry about calling it, just put this in the same controller as your two async methods, and when they complete successfully (this is where the deferred.resolve() occurs ), they will let the $q service know. Once all of your promises have resolved, $q will call your callback function, and set loading to false. Hope this helps, let me know if there's anything I can clarify. – B Cotter Oct 16 '13 at 07:59
0

Just set some boolean flag on when your controller is being instantiated and reset this flag in your success/error functions.

.controller('MyCtrl', function ( $scope ) {
  $scope.isLoading = true;
  $http({ method: 'GET', url: url })
            .success(function (data, status, headers, config) {
                $scope.option.subjects = data;
                $scope.isLoading = false;
            })
            .error(function (data, status, headers, config) {
                alert("Error: No data returned from " + url);
                $scope.isLoading = false;
            });
});

Use ng-show with this flag to show your loading thingy.

devmiles.com
  • 9,895
  • 5
  • 31
  • 47
  • The problem is that I have more than one loading that takes place when setting up. Setting isLoading = false on one does not help if the other is still loading. – Samantha J T Star Oct 15 '13 at 16:46
  • Promises are cool but for a simpler approach you may just set isLoading = 2 and decrement it in each time something completes. – devmiles.com Oct 16 '13 at 09:28