ZioBudda
ZioBudda

Reputation: 948

Angularjs $http and progress bar

I need to upload file and I use $http (this code is get from my .service() function):

sendFile: function (params) {
            return $http({method : 'post',
                url : 'http://XXXXXXXXXXXXX/rest/file.json',
                headers : { 'X-CSRF-Token' : $cookies['csrftoken']},
                data : params
            })
        },

Now, for little file and a good line there is no problem, but with a big file and/or a bad/slow line there is a problem of UI: user can not know when upload will be end. I need a progress bar.

So I have search on internet, but I have not found a solution. Is there a possibility to get some progress/notification from $http ?

I have tried this code without luck:

ProfileService.sendFile(data)
                    .then(function(ret) {
                            var uri = ret.data.uri;
                            scope.content = "Upload finished";

                            scope.postForm.fid = ret.data.fid;
                            scope.postForm.buttonDisabled = false;
                        },
                        function(error) {
                            scope.postForm.showError = true;
                            scope.postForm.errorMsg = error.data;
                        },
                        function(progress) {
                            console.log("inside progress");
                            console.log(progress)
                        }
                    );

“progress” function is never called.

I'm using angular 1.2.x

Thanks.

Upvotes: 37

Views: 79536

Answers (5)

Ali Adravi
Ali Adravi

Reputation: 22833

If you don't want to write show hide in every single http method, then we can create a simple directive by using $http.pendingRequests.length and and that's it.

Whenever we will have any http request in progress it will be showing automatically.

app.directive('loading', ['$http', function ($http) {
    return {
        restrict: 'A',
        link: function (scope, elm, attrs) {
            scope.isLoading = function () {
                return $http.pendingRequests.length > 0;
            };
            scope.$watch(scope.isLoading, function (v) {
                if (v) {
                    elm.show();
                } else {
                    elm.hide();
                }
            });
        }
    };
}]);

AND HTML

 <div data-loading>
   Please wait...
 </div>

For more detail see this

Upvotes: 1

german meza
german meza

Reputation: 31

You can simply use the eventHandlers of the $http service

like:

mainModule.service('File', function (Api) {

    var controller = 'files';

    function File(data) {
        this.$data = data;
    }

    File.__proto__ = File.prototype = {
        upload: function (progress) {
            var fd = new FormData();
            fd.append('file', this.$data);
            return pack('/upload').post(fd, {
                transformRequest: angular.identity,
                uploadEventHandlers: {'progress': progress},
                headers: {'Content-Type': undefined}
            });
        }
    };

    return File;
    function pack(action) {
        return Api(controller + action);
    }
});

Api is a service to connect with the server api.

$data is the file object from the input

Upvotes: 2

Muhammad Reda
Muhammad Reda

Reputation: 27053

You can use Angular Loading Bar. It works automatically for $http requests and does not need any setup except adding it as app dependency.

angular.module('app', ['angular-loading-bar']); // that's all

Upvotes: 51

aludvigsen
aludvigsen

Reputation: 5991

You can solve this by hiding/showing a loadingbar. Start showing the loadingbar once the upload starts, and remove the loadingbar when the upload is done (in the success handler from the $http request).

I created a simple jsfiddle for you to show you an example.
I'm using $timeout to simulate a $http request.

Html markup:

<div ng-controller="MyCtrl">
    <!-- this can be an image if you want -->
    <p ng-show="loading">...LOADING...</p>

    <!-- Showing the status -->
    <p ng-hide="loading">{{status}}</p>
    <button type="button" ng-click="upload()">Do $http request</button>
</div>

Js Controller:

function MyCtrl($scope, $timeout) {
    $scope.status = 'Not started';
    $scope.loading = false;

    $scope.upload = function() {
        $scope.loading = true;
        // Simulating a http request with a timeout
        $timeout(function(){ 
            $scope.status = "Finished";
            $scope.loading = false;
        },3000);
    }
}

For a demonstration of how this works, see this fiddle.

Update

By clarification in the comments, you want to be able to track the progress on the upload by percentage. eg. How many % til the upload is finished

You should check out this SO post where this has already been discussed.

From the accepted answer:

I don't think $http.post() can be used for this. As for client-side, it should work with an HTML5 browser, but you'll probably have to create your own XMLHttpRequest object and onprogress listener. See AngularJS: tracking status of each file being uploaded simultaneously for ideas.

Upvotes: 3

mithun_daa
mithun_daa

Reputation: 4384

I would highly recommend ng-progress. This handles multiple requests and basically shows a neat little progress bar for all http activity.

http://victorbjelkholm.github.io/ngProgress/

Upvotes: 6

Related Questions