【问题标题】:$http upload file progress in AngularJS$http 在 AngularJS 中上传文件进度
【发布时间】:2013-01-12 02:39:35
【问题描述】:

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

【问题讨论】:

  • 您需要准确的信息,例如“完成 10%”,然后是“完成 25%”等,还是只需要某种动画图形来表明工作正在进行?

标签: angularjs


【解决方案1】:

使用纯角度:

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】:

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

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

    【讨论】:

    【解决方案3】:

    您还可以使用简单/轻量级的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);
          }); 
        }
      }
    }];
    

    【讨论】:

    • 没有。在.net 中尝试过的解决方案。每个文件我只能得到 100%。没有进展(11%、25%)@danial 你有没有在.net 中取得进展的例子。我必须在服务器端更改 spmething 吗?进度 callbacl 只报告 100%
    • 查看 wiki 页面 github.com/danialfarid/ng-file-upload#net 并在 github 问题上发布您的问题。您可能需要更改一些服务器设置和代理才能报告进度。
    • 在其他项目(也是.NET)中,我的同事使用了github.com/blueimp/jQuery-File-Upload,并且文件进度正常。
    • 或者可能是我的上传速度太快,看不到进度
    • @Vlado ,我在onprogress 上使用了scope.$apply(...) 来显示百分比范围。
    【解决方案4】:

    你可以在我使用简单的角度函数上传文件和 $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);
     }) 
    }
    

    【讨论】:

      【解决方案5】:

      我认为 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;
      });
      

      【讨论】:

        【解决方案6】:

        这是另一个解决方案:

        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-09-22
          • 1970-01-01
          • 1970-01-01
          • 2016-05-04
          • 2010-11-20
          • 2017-07-26
          • 2012-01-01
          • 1970-01-01
          相关资源
          最近更新 更多