AngularJS:如何使用multipart表单实现简单的文件上传?

时间:2012-12-19 23:35:57

标签: angularjs angularjs-fileupload

我想从AngularJS到node.js服务器做一个简单的多部分表单帖子, 表单应包含一个部分中的JSON对象和另一部分中的图像, (我目前只发布带有$ resource的JSON对象)

我想我应该从输入类型="文件"开始,但后来发现AngularJS无法绑定到那个..

我能找到的所有例子都是用于包装用于拖放的jQuery插件。下降。我想简单上传一个文件。

我是AngularJS的新手,并且在编写我自己的指令时感到不舒服。

7 个答案:

答案 0 :(得分:182)

一个真正有效的解决方案,没有其他依赖关系而不是angularjs(使用v.1.0.6测试)

<强> HTML

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>

Angularjs(1.0.6)不支持“输入文件”标签上的 ng-model ,因此您必须以“本地方式”执行此操作,以传递所有(最终)所选文件来自用户。

<强>控制器

$scope.uploadFile = function(files) {
    var fd = new FormData();
    //Take the first selected file
    fd.append("file", files[0]);

    $http.post(uploadUrl, fd, {
        withCredentials: true,
        headers: {'Content-Type': undefined },
        transformRequest: angular.identity
    }).success( ...all right!... ).error( ..damn!... );

};

很酷的部分是 undefined 内容类型和 transformRequest:angular.identity ,它们在$ http中为选择正确的“内容类型”提供了能力并管理处理多部分数据时所需的边界。

答案 1 :(得分:42)

您可以使用简单/轻量级ng-file-upload指令。 它支持使用FileAPI flash shim的非HTML5浏览器的拖放,文件进度和文件上传

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

JS:

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

var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
  $scope.onFileSelect = function($files) {
  Upload.upload({
    url: 'my/upload/url',
    file: $files,            
  }).progress(function(e) {
  }).then(function(data, status, headers, config) {
    // file is uploaded successfully
    console.log(data);
  }); 

}];

答案 2 :(得分:7)

直接发送文件效率更高。

Content-Type: multipart/form-data的{​​{3}}会增加额外33%的开销。如果服务器支持它,则更有效地直接发送文件:

$scope.upload = function(url, file) {
    var config = { headers: { 'Content-Type': undefined },
                   transformResponse: angular.identity
                 };
    return $http.post(url, file, config);
};

发送带有base64 encoding的POST时,设置'Content-Type': undefined非常重要。然后,File object会检测XHR send method并自动设置内容类型。

要发送多个文件,请参阅File object

  

我想我应该从input type =“file”开始,但后来发现AngularJS无法绑定到那个..

默认情况下,<input type=file>元素不会与Doing Multiple $http.post Requests Directly from a FileList一起使用。它需要ng-model directive

使用ng-model custom directive

的“select-ng-files”指令的工作演示

angular.module("app",[]);

angular.module("app").directive("selectNgFiles", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function(e) {
        var files = elem[0].files;
        ngModel.$setViewValue(files);
      })
    }
  }
});
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app">
    <h1>AngularJS Input `type=file` Demo</h1>
    
    <input type="file" select-ng-files ng-model="fileArray" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileArray">
      {{file.name}}
    </div>
  </body>

内容类型为$http.post

multipart/form-data

如果必须发送multipart/form-data

<form role="form" enctype="multipart/form-data" name="myForm">
    <input type="text"  ng-model="fdata.UserName">
    <input type="text"  ng-model="fdata.FirstName">
    <input type="file"  select-ng-files ng-model="filesArray" multiple>
    <button type="submit" ng-click="upload()">save</button>
</form>
$scope.upload = function() {
    var fd = new FormData();
    fd.append("data", angular.toJson($scope.fdata));
    for (i=0; i<$scope.filesArray.length; i++) {
        fd.append("file"+i, $scope.filesArray[i]);
    };

    var config = { headers: {'Content-Type': undefined},
                   transformRequest: angular.identity
                 }
    return $http.post(url, fd, config);
};

使用1发送POST时,设置'Content-Type': undefined非常重要。然后,FormData API将检测FormData对象,并使用XHR send method自动将内容类型标头设置为multipart/form-data

答案 3 :(得分:5)

我刚遇到这个问题。所以有一些方法。首先是新浏览器支持

var formData = new FormData();

Follow this link to a blog with info about支持仅限于现代浏览器,但完全解决了这个问题。

否则,您可以使用target属性将表单发布到iframe。 发布表单时,请确保将目标设置为iframe,并将其display属性设置为none。 目标是iframe的名称。 (只是你知道。)

我希望这会有所帮助

答案 4 :(得分:2)

我知道这是一个迟到的条目,但我创建了一个简单的上传指令。您可以立即开始工作!

<input type="file" multiple ng-simple-upload web-api-url="/api/post"
       callback-fn="myCallback" />

ng-simple-upload更多关于Github的例子,使用Web API。

答案 5 :(得分:1)

我刚刚在AngularJs中为一个简单的上传器编写了一个简单的指令(来自现有的一个)。

(确切的jQuery上传器插件是https://github.com/blueimp/jQuery-File-Upload

A Simple Uploader using AngularJs (with CORS Implementation)

(虽然服务器端用于PHP,但您也可以简单地更改它节点)

答案 6 :(得分:1)

您可以通过将数据分配给资源$resource的params属性来通过actions上传,如下所示:

$scope.uploadFile = function(files) {
    var fdata = new FormData();
    fdata.append("file", files[0]);

    $resource('api/post/:id', { id: "@id" }, {
        postWithFile: {
            method: "POST",
            data: fdata,
            transformRequest: angular.identity,
            headers: { 'Content-Type': undefined }
        }
    }).postWithFile(fdata).$promise.then(function(response){
         //successful 
    },function(error){
        //error
    });
};