简体   繁体   中英

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.

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

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/

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM