Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular $http, $q: track progress

Tags:

ajax

angularjs

Is there a way to track progress of http requests with Angular $http and $q? I'm making $http calls from a list of urls and then using $q.all I'm returning result of all requests. I would like to track progress of each request (promise resolved) so that I can show some progress to the user. I'm thinking of emitting event when a promise gets resolved but I'm not sure where should that be.

        var d = $q.defer();
        var promises = [];
        for(var i = 0; i < urls.length; i++){
            var url = urls[i];
            var p = $http.get(url, {responseType: "arraybuffer"});
            promises.push(p);
        }
        $q.all(promises).then(function(result){
            d.resolve(result);
        }, function(rejection){
            d.reject(rejection);
        });
        return d.promise;

EDIT: OK, after a bit of fiddling, this is what I've come up with

        var d = $q.defer();
        var promises = [];
        var completedCount = 0;
        for(var i = 0; i < urls.length; i++){
            var url = urls[i];
            var p = $http.get(url, {responseType: "arraybuffer"}).then(function(respose){
              completedCount = completedCount+1;
              var progress = Math.round((completedCount/urls.length)*100);
              $rootScope.$broadcast('download.completed', {progress: progress});
              return respose;
            }, function(error){
              return error;
            });
            promises.push(p);
        }
        $q.all(promises).then(function(result){
            d.resolve(result);
        }, function(rejection){
            d.reject(rejection);
        });
        return d.promise;

Not sure if it is the right way of doing it.

like image 345
Amitava Avatar asked Dec 26 '22 23:12

Amitava


1 Answers

I see you have already edit your own code, but if you need a more overall solution, keep reading

I once made a progress solution based on all pending http request (showing a indicator that something is loading, kind of like youtube has on the top progress bar)

js:

app.controller("ProgressCtrl", function($http) {

    this.loading = function() {
        return !!$http.pendingRequests.length;
    };

});

html:

<div id="fixedTopBar" ng-controller="ProgressCtrl as Progress">
    <div id="loading" ng-if="Progress.loading()">
        loading...
    </div>
</div>

.

Hardcore

For my latest project it wasn't just enought with just request calls. I started to get into sockets, webworker, filesystem, filereader, dataChannel and any other asynchronous calls that use $q. So i start looking into how i could get all the pending promises (including $http). Turns out there wasn't any angular solution, so i kind of monkey patched the $q provider by decorating it.

app.config(function($provide) {

    $provide.decorator("$q", function($delegate) {
        // $delegate == original $q service

        var orgDefer = $delegate.defer;
        $delegate.pendingPromises = 0;

        // overide defer method 
        $delegate.defer = function() {
            $delegate.pendingPromises++; // increass
            var defer = orgDefer();

            // decreass no mather of success or faliur
            defer.promise['finally'](function() {
                $delegate.pendingPromises--;
            });

            return defer;
        }

        return $delegate
    });

});

app.controller("ProgressCtrl", function($q) {

    this.loading = function() {
        return !!$q.pendingPromises;
    };

});

This may not perhaps fit everyone needs for production but it could be useful to developers to see if there is any unresolved issues that has been left behind and never gets called

like image 59
Endless Avatar answered Jan 22 '23 15:01

Endless