AngularJS中的$ http上传文件进度

时间:2013-01-12 02:39:36

标签: angularjs

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

6 个答案:

答案 0 :(得分:17)

您还可以使用简单/轻量级angular-file-upload指令来处理这些内容。 它支持使用FileAPI flash shim对非HTML5浏览器进行拖放,文件进度/中止和文件上传

<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);
      }); 
    }
  }
}];

答案 1 :(得分:16)

使用纯角度:

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) + '%');
});

答案 2 :(得分:15)

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

至于客户端,它应该与HTML5浏览器一起使用,但您可能必须创建自己的XMLHttpRequest对象和onprogress侦听器。有关提示,请参阅AngularJS: tracking status of each file being uploaded simultaneously

答案 3 :(得分:3)

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

我认为最好的办法是使用像jQuery File Upload这样的东西。解决方案的一个想法是创建一个Service,它返回{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;
});

答案 4 :(得分: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()。我怀疑这会改变,所以上面的垫片式代码应该可以正常工作。

  • 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(...);
  • 或者,您可以将这两种方法与上述代码进行一些修改相结合。

答案 5 :(得分: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);
 }) 
}