【问题标题】:Angularjs how to upload multipart form data and a file?Angularjs如何上传多部分表单数据和文件?
【发布时间】:2014-08-18 01:22:42
【问题描述】:

我是 angular.js 的初学者,但我对基础知识掌握得很好。

我要做的是上传一个文件和一些表单数据作为多部分表单数据。我读到这不是 Angular 的功能,但是 3rd 方库可以完成这项工作。我已经通过 git 克隆了 angular-file-upload,但是我仍然无法发布简单的表单和文件。

谁能提供一个例子,html和js如何做到这一点?

【问题讨论】:

  • 能否请您发布一个指向该特定插件的链接,以便我也可以使用它。当你在 git 上搜索“angular-file-upload”时,目前有 83 个结果。

标签: javascript forms angularjs post multipartform-data


【解决方案1】:

这只是该项目演示页面的副本,并显示在表单提交中上传单个文件以及上传进度。

(function (angular) {
'use strict';

angular.module('uploadModule', [])
    .controller('uploadCtrl', [
        '$scope',
        '$upload',
        function ($scope, $upload) {
            $scope.model = {};
            $scope.selectedFile = [];
            $scope.uploadProgress = 0;

            $scope.uploadFile = function () {
                var file = $scope.selectedFile[0];
                $scope.upload = $upload.upload({
                    url: 'api/upload',
                    method: 'POST',
                    data: angular.toJson($scope.model),
                    file: file
                }).progress(function (evt) {
                    $scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);
                }).success(function (data) {
                    //do something
                });
            };

            $scope.onFileSelect = function ($files) {
                $scope.uploadProgress = 0;
                $scope.selectedFile = $files;
            };
        }
    ])
    .directive('progressBar', [
        function () {
            return {
                link: function ($scope, el, attrs) {
                    $scope.$watch(attrs.progressBar, function (newValue) {
                        el.css('width', newValue.toString() + '%');
                    });
                }
            };
        }
    ]);
 }(angular));

HTML

<form ng-submit="uploadFile()">
   <div class="row">
         <div class="col-md-12">
                  <input type="text" ng-model="model.fileDescription" />
                  <input type="number" ng-model="model.rating" />
                  <input type="checkbox" ng-model="model.isAGoodFile" />
                  <input type="file" ng-file-select="onFileSelect($files)">
                  <div class="progress" style="margin-top: 20px;">
                    <div class="progress-bar" progress-bar="uploadProgress" role="progressbar">
                      <span ng-bind="uploadProgress"></span>
                      <span>%</span>
                    </div>
                  </div>

                  <button button type="submit" class="btn btn-default btn-lg">
                    <i class="fa fa-cloud-upload"></i>
                    &nbsp;
                    <span>Upload File</span>
                  </button>
                </div>
              </div>
            </form>

编辑:在文件 post 中添加了将模型传递到服务器。

输入元素中的表单数据将在帖子的 data 属性中发送,并可作为普通表单值使用。

【讨论】:

  • 嗨,乔恩,我绝对可以让文件正常工作,但是如何在 html 中添加一个文本字段,然后将其提取为 angular 并将其添加到提交文件的帖子中?跨度>
  • 能否请您发布指向您所指的插件的链接。
  • 同意,如果没有插件,这个答案很有价值。
  • 你用什么插件? $upload 是从哪里来的??
  • 我相信这是来自 angular-file-upload。问题中提到的 OP 的回购
【解决方案2】:

首先

  1. 您不需要对结构进行任何特殊更改。我的意思是:html 输入标签。

<input accept="image/*" name="file" ng-value="fileToUpload"
       value="{{fileToUpload}}" file-model="fileToUpload"
       set-file-data="fileToUpload = value;" 
       type="file" id="my_file" />

1.2 创建自己的指令,

.directive("fileModel",function() {
	return {
		restrict: 'EA',
		scope: {
			setFileData: "&"
		},
		link: function(scope, ele, attrs) {
			ele.on('change', function() {
				scope.$apply(function() {
					var val = ele[0].files[0];
					scope.setFileData({ value: val });
				});
			});
		}
	}
})
  1. 在带有 $httpProvider 的模块中,使用 multipart/form-data 添加依赖项,例如(Accept、Content-Type 等)。 (建议是,接受 json 格式的响应) 例如:

$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript'; $httpProvider.defaults.headers.post['Content-Type'] = 'multipart/form-data; charset=utf-8';

  1. 然后在控制器中创建单独的函数来处理表单提交调用。 比如下面的代码:

  2. 在服务函数中故意处理“responseType”参数,以便服务器不应该抛出“byteerror”。

  3. transformRequest,修改带有附加标识的请求格式。

  4. withCredentials : false,用于 HTTP 身份验证信息。

in controller:

  // code this accordingly, so that your file object 
  // will be picked up in service call below.
  fileUpload.uploadFileToUrl(file); 


in service:

  .service('fileUpload', ['$http', 'ajaxService',
    function($http, ajaxService) {

      this.uploadFileToUrl = function(data) {
        var data = {}; //file object 

        var fd = new FormData();
        fd.append('file', data.file);

        $http.post("endpoint server path to whom sending file", fd, {
            withCredentials: false,
            headers: {
              'Content-Type': undefined
            },
            transformRequest: angular.identity,
            params: {
              fd
            },
            responseType: "arraybuffer"
          })
          .then(function(response) {
            var data = response.data;
            var status = response.status;
            console.log(data);

            if (status == 200 || status == 202) //do whatever in success
            else // handle error in  else if needed 
          })
          .catch(function(error) {
            console.log(error.status);

            // handle else calls
          });
      }
    }
  }])
&lt;script src="//unpkg.com/angular/angular.js"&gt;&lt;/script&gt;

【讨论】:

  • 这对 +1 很有帮助
  • 谢谢#husamuddin。我希望它能消除许多相关的疑虑。
  • 标题:{ 'Content-Type': undefined }
  • 如果我想自己设置边界,而不是使用 'Content-Type': undefined 并让 angular 自己决定怎么办?在这种情况下,$http 中的 headers 属性将包含什么?
  • 如果要保持默认,则无需指定。否则保留应用程序/json;默认在应用程序的根函数中。
【解决方案3】:

直接发送文件效率更高。

Content-Type: multipart/form-database64 encoding 增加了 33% 的额外开销。如果服务器支持,直接发送文件效率更高:

直接从FileList 执行多个$http.post 请求

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

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


ng-model一起使用的“select-ng-files”指令的工作演示1

&lt;input type=file&gt; 元素默认情况下不适用于ng-model directive。它需要一个custom directive:

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="fileList" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileList">
      {{file.name}}
    </div>
  </body>

【讨论】:

    【解决方案4】:

    您可以查看此方法,将图像和表单数据一起发送

    <div class="form-group ml-5 mt-4" ng-app="myApp" ng-controller="myCtrl">
                        <label for="image_name">Image Name:</label>
                        <input type="text"   placeholder="Image name" ng-model="fileName" class="form-control" required>
                        <br>
    
                        <br>
                        <input id="file_src" type="file"   accept="image/jpeg" file-input="files"   >
                        <br>
                            {{file_name}}
                <img class="rounded mt-2 mb-2 " id="prvw_img" width="150" height="100" >
                        <hr>
                          <button class="btn btn-info" ng-click="uploadFile()">Upload</button>
                            <br>
    
                           <div ng-show = "IsVisible" class="alert alert-info w-100 shadow mt-2" role="alert">
                  <strong> {{response_msg}} </strong>
                </div>
                                <div class="alert alert-danger " id="filealert"> <strong> File Size should be less than 4 MB </strong></div>
                        </div>
    

    Angular JS 代码

        var app = angular.module("myApp", []);
     app.directive("fileInput", function($parse){
          return{
               link: function($scope, element, attrs){
                    element.on("change", function(event){
                         var files = event.target.files;
    
    
                         $parse(attrs.fileInput).assign($scope, element[0].files);
                         $scope.$apply();
                    });
               }
          }
     });
     app.controller("myCtrl", function($scope, $http){
          $scope.IsVisible = false;
          $scope.uploadFile = function(){
               var form_data = new FormData();
               angular.forEach($scope.files, function(file){
                    form_data.append('file', file); //form file
                                    form_data.append('file_Name',$scope.fileName); //form text data
               });
               $http.post('upload.php', form_data,
               {
                    //'file_Name':$scope.file_name;
                    transformRequest: angular.identity,
                    headers: {'Content-Type': undefined,'Process-Data': false}
               }).success(function(response){
                 $scope.IsVisible = $scope.IsVisible = true;
                          $scope.response_msg=response;
                   // alert(response);
                   // $scope.select();
               });
          }
    
     });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-13
      • 2012-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 2016-06-29
      相关资源
      最近更新 更多