25

如何从上传图像的 AngularJS $http POST 请求中获取“进度”事件?是否可以在客户端执行此操作,或者我是否需要服务器在接收数据时报告进度?

4

6 回答 6

21

使用纯角度:

function upload(data) {
    var formData = new FormData();
    Object.keys(data).forEach(function(key){formData.append(key, data[key]);});
    var defer = $q.defer();
    $http({
        method: 'POST',
        data: formData,
        url: <url>,
        headers: {'Content-Type': undefined},
        uploadEventHandlers: { progress: function(e) {
            defer.notify(e.loaded * 100 / e.total);
        }}
    }).then(defer.resolve.bind(defer), defer.reject.bind(defer));
    return defer.promise;
}

和其他地方......

// file is a JS File object
upload({avatar:file}).then(function(responce){
    console.log('success :) ', response);
}, function(){
    console.log('failed :(');
}, function(progress){
    console.log('uploading: ' + Math.floor(progress) + '%');
});
于 2017-01-30T06:26:20.890 回答
17

You can also use the simple/lightweight angular-file-upload directive that takes care of these stuff. It supports drag&drop, file progress/abort and file upload for non-HTML5 browsers with FileAPI flash shim

<div ng-controller="MyCtrl">
  <input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>

JS:

//inject angular file upload directive.
angular.module('myApp', ['angularFileUpload']);

var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
  $scope.onFileSelect = function($files) {
    //$files: an array of files selected, each file has name, size, and type.
    for (var i = 0; i < $files.length; i++) {
      var $file = $files[i];
      $upload.upload({
        url: 'my/upload/url',
        file: $file,
        progress: function(e){}
      }).then(function(data, status, headers, config) {
        // file is uploaded successfully
        console.log(data);
      }); 
    }
  }
}];
于 2013-11-14T18:08:02.783 回答
15

我不认为 $http.post() 可以用于此。

至于客户端,它应该与 HTML5 浏览器一起使用,但您可能必须创建自己的 XMLHttpRequest 对象和onprogress侦听器。请参阅AngularJS:跟踪同时上传的每个文件的状态以获取想法。

于 2013-01-12T03:48:41.307 回答
3

我认为 Angular 没有内置的东西来处理上传。

我认为你最好的选择是使用jQuery File Upload 之类的东西。解决方案的一个想法是创建一个{progress:0}默认返回的服务,然后在其内部实现 jQuery File Upload 的进度更新回调,然后简单地不断更新进度。由于 Angular 的绑定,上传进度会同步。

angular.module('myApp.services', [])
  .factory('Uploader', function() {
  var uploaderService = {};

  var status = { progress: 0 };

  uploaderService.upload = function(inputEl) {
    inputEl.fileupload({
      /* ... */
      progressall: function (e, data) {
        status.progress = parseInt(data.loaded / data.total * 100, 10);
      }
    });
  };

  return uploaderService;
});
于 2013-01-12T14:09:18.910 回答
2

这是另一个解决方案:

window.XMLHttpRequest = (function (orig) {
    if (orig) {
        var intercept = [],
            result = function () {
            var r = new orig();

            if (r.upload) {
                $(r).on(
                    'abort error load loadend loadstart progress',
                    function (e) {
                        $(document).trigger('upload.XHR', e);
                    }
                );
            }

            if (intercept.length) {
                intercept[0].push({
                    request:r
                });
            }

            return r;
        };

        result.grab = function (f) {
            intercept.unshift([]);
            f();
            return intercept.shift();
        };

        return result;
    }

    return function () {
        try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
        throw new Error("This browser does not support XMLHttpRequest.");
    };
}(window.XMLHttpRequest));

笔记:

  • AngularJS 当前将引用存储window.XMLHttpRequest为私有XHR变量,然后像这样使用它new XHR():我怀疑这会不会改变,所以上面类似 shim 的代码应该可以正常工作。

  • Mozilla 有一些扩展:XMLHttpRequest接受可选参数。上面的代码没有处理这个问题,但是 AngularJS 并没有使用这些扩展。

  • 一种可能的用途(如果您想显示所有当前请求,并可能实现一些“取消”按钮):

$(document).on('upload.XHR', function (_e, e) {
   switch (e.type) {
       // do your thing here
   }
});
  • 另一种可能的用途:
var list = window.XMLHttpRequest.grab(function () {
    // start one or more $http requests here, or put some code
    // here that indirectly (but synchronously) starts requests
    $http.get(...);
    couchDoc.save();
    couchDoc.attach(blob, 'filename.ext');
    // etc
});

list[0].request.upload.addEventListener(...);
  • 或者,您可以将这两种方法与对上面代码的一些修改结合起来。
于 2013-03-23T19:42:56.830 回答
0

你可以在我使用简单的角度函数上传文件和 $scope.progressBar 变量来检查上传进度的地方使用它...

$scope.functionName = function(files) {
   var file = files[0];
   $scope.upload = $upload.upload({
   url: 'url',
   method: 'POST', 
   withCredentials: true, 
   data: {type:'uploadzip'},
   file: file, // or list of files ($files) for html5 only 
 }).progress(function(evt) {
   console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
   $scope.progressBar = parseInt(100.0 * evt.loaded / evt.total);
 }).success(function(data, status, headers, config) {
   console.log('upload succesfully...')
 }).error(function(err) {
   console.log(err.stack);
 }) 
}
于 2016-04-04T10:50:21.507 回答