Angularjs $http and progress bar

2019-02-02 20:09发布

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.

5条回答
一纸荒年 Trace。
2楼-- · 2019-02-02 20:27

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

查看更多
▲ chillily
3楼-- · 2019-02-02 20:30

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/

查看更多
你好瞎i
4楼-- · 2019-02-02 20:35

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

查看更多
女痞
5楼-- · 2019-02-02 20:44

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
查看更多
叛逆
6楼-- · 2019-02-02 20:46

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.

查看更多
登录 后发表回答