Angularjs如何上传多部分表单数据和文件?
Posted
技术标签:
【中文标题】Angularjs如何上传多部分表单数据和文件?【英文标题】:Angularjs how to upload multipart form data and a file? 【发布时间】:2014-08-18 01:22:42 【问题描述】:我是 angular.js 的初学者,但我对基础知识掌握得很好。
我要做的是上传一个文件和一些表单数据作为多部分表单数据。我读到这不是 Angular 的功能,但是 3rd 方库可以完成这项工作。我已经通过 git 克隆了 angular-file-upload,但是我仍然无法发布简单的表单和文件。
谁能提供一个例子,html和js如何做到这一点?
【问题讨论】:
能否请您发布一个指向该特定插件的链接,以便我也可以使用它。当你在 git 上搜索“angular-file-upload”时,目前有 83 个结果。 【参考方案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>
<span>Upload File</span>
</button>
</div>
</div>
</form>
编辑:在文件 post 中添加了将模型传递到服务器。
输入元素中的表单数据将在帖子的 data 属性中发送,并可作为普通表单值使用。
【讨论】:
嗨,乔恩,我绝对可以让文件正常工作,但是如何在 html 中添加一个文本字段,然后将其提取为 angular 并将其添加到提交文件的帖子中?跨度> 能否请您发布指向您所指的插件的链接。 同意,如果没有插件,这个答案很有价值。 你用什么插件? $upload 是从哪里来的?? 我相信这是来自 angular-file-upload。问题中提到的 OP 的回购【参考方案2】:首先
-
您不需要对结构进行任何特殊更改。我的意思是: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 );
);
);
)
-
在带有 $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';
然后在控制器中创建单独的函数来处理表单提交调用。 比如下面的代码:
在服务函数中故意处理“responseType”参数,以便服务器不应该抛出“byteerror”。
transformRequest,修改带有附加标识的请求格式。
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
);
])
<script src="//unpkg.com/angular/angular.js"></script>
【讨论】:
这对 +1 很有帮助 谢谢#husamuddin。我希望它能消除许多相关的疑虑。 标题: 'Content-Type': undefined 如果我想自己设置边界,而不是使用'Content-Type': undefined
并让 angular 自己决定怎么办?在这种情况下,$http
中的 headers
属性将包含什么?
如果要保持默认,则无需指定。否则保留应用程序/json;默认在应用程序的根函数中。【参考方案3】:
直接发送文件效率更高。
Content-Type: multipart/form-data
的 base64 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
<input type=file>
元素默认情况下不适用于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" >
<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();
);
);
【讨论】:
以上是关于Angularjs如何上传多部分表单数据和文件?的主要内容,如果未能解决你的问题,请参考以下文章
使用 AngularJS 和 SpringMVC 进行多部分文件上传
如何使用多部分/表单和分块编码在 spring mvc 中接收文件上传?
上传多部分表单数据时如何观察uploadProgress? [复制]