使用AngularJS上传文件
这是我的HTML表单:
<form name="myForm" ng-submit=""> <input ng-model='file' type="file"/> <input type="submit" value='Submit'/> </form>
我想从本地机器上传图片,并想读取上传文件的内容。 所有这一切,我想用AngularJS做。
当我尝试打印$scope.file
的值时,它是未定义的。
这里的一些答案build议使用FormData()
,但不幸的是,这是一个浏览器对象在Internet Explorer 9及以下版本中不可用。 如果您需要支持那些较旧的浏览器,则需要使用<iframe>
或Flash等备份策略。
已经有很多的Angular.js模块来执行file upload。 这两个对旧版浏览器有明确的支持:
- https://github.com/leon/angular-upload – 使用iframe作为后备
- https://github.com/danialfarid/ng-file-upload-使用FileAPI / Flash作为后备
还有其他一些选项:
- https://github.com/nervgh/angular-file-upload/
- https://github.com/uor/angular-file
- https://github.com/twilson63/ngUpload
- https://github.com/uploadcare/angular-uploadcare
其中一个应该适合您的项目,或者可以让您了解如何自己编写代码。
最简单的就是使用HTML5 API,即FileReader
HTML非常简单:
<input type="file" id="file" name="file"/> <button ng-click="add()">Add</button>
在你的控制器中定义'add'方法:
$scope.add = function() { var f = document.getElementById('file').files[0], r = new FileReader(); r.onloadend = function(e) { var data = e.target.result; //send your binary data via $http or $resource or do anything else with it } r.readAsBinaryString(f); }
浏览器兼容性
桌面浏览器
Firefox(Gecko)3.6(1.9.2),Chrome 7,Internet Explorer * 10,Opera * 12.02,Safari 6.0.2
移动浏览器
Firefox(Gecko)32,Chrome 3,Internet Explorer * 10,Opera * 11.5,Safari 6.1
注意:不推荐使用readAsBinaryString()方法,而应使用readAsArrayBuffer() 。
这是2015年的方式,没有第三方图书馆。 适用于所有最新的浏览器。
app.directive('myDirective', function (httpPostFactory) { return { restrict: 'A', scope: true, link: function (scope, element, attr) { element.bind('change', function () { var formData = new FormData(); formData.append('file', element[0].files[0]); httpPostFactory('upload_image.php', formData, function (callback) { // recieve image name to use in a ng-src console.log(callback); }); }); } }; }); app.factory('httpPostFactory', function ($http) { return function (file, data, callback) { $http({ url: file, method: "POST", data: data, headers: {'Content-Type': undefined} }).success(function (response) { callback(response); }); }; });
HTML:
<input data-my-Directive type="file" name="file">
PHP:
if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { // uploads image in the folder images $temp = explode(".", $_FILES["file"]["name"]); $newfilename = substr(md5(time()), 0, 10) . '.' . end($temp); move_uploaded_file($_FILES['file']['tmp_name'], 'images/' . $newfilename); // give callback to your angular code with the image src name echo json_encode($newfilename); }
js小提琴(只有前端) https://jsfiddle.net/vince123/8d18tsey/31/
以下是file upload的工作示例:
http://jsfiddle.net/vishalvasani/4hqVu/
在这个函数中调用
setFiles
从视图将更新控制器中的文件数组
要么
您可以使用AngularJS检查jQueryfile upload
您可以使用flow.js实现漂亮的文件和文件夹上传。
https://github.com/flowjs/ng-flow
看看这里的演示
http://flowjs.github.io/ng-flow/
它不支持IE7,IE8,IE9,所以你最终将不得不使用兼容层
我尝试了@Anoyz(正确答案)给出的所有替代方法…最好的解决scheme是https://github.com/danialfarid/angular-file-upload
一些特点:
- 进展
- Multifiles
- 字段
- 旧浏览器(IE8-9)
这对我来说工作很好。 你只需要注意说明。
在服务器端,我使用NodeJs,Express 4和Multer中间件来pipe理多部分请求。
使用onchange
事件将input文件元素传递给你的函数。
<input type="file" onchange="angular.element(this).scope().fileSelected(this)" />
所以,当用户select一个文件,你有一个引用,而不需要用户点击“添加”或“上传”button。
$scope.fileSelected = function (element) { var myFileSelected = element.files[0]; };
<form ng-controller = "myCtrl"> <input type = "file" file-model="files" multiple/> <button ng-click = "uploadFile()">upload me</button> <li ng-repeat="file in files">{{file.name}}</li> </form> <script src = "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script> <script> angular.module('myApp', []).directive('fileModel', ['$parse', function ($parse) { return { restrict: 'A', link: function(scope, element, attrs) { element.bind('change', function(){ $parse(attrs.fileModel).assign(scope,element[0].files) scope.$apply(); }); } }; }]).controller('myCtrl', ['$scope', '$http', function($scope, $http){ $scope.uploadFile=function(){ var fd=new FormData(); console.log($scope.files); angular.forEach($scope.files,function(file){ fd.append('file',file); }); $http.post('http://localhost:1337/mediaobject/upload',fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }).success(function(d){ console.log(d); }) } }]); </script>
容易与指令
HTML:
<input type="file" file-upload multiple/>
JS:
app.directive('fileUpload', function () { return { scope: true, //create a new scope link: function (scope, el, attrs) { el.bind('change', function (event) { var files = event.target.files; //iterate files since 'multiple' may be specified on the element for (var i = 0;i<files.length;i++) { //emit event upward scope.$emit("fileSelected", { file: files[i] }); } }); } };
在指令中,我们确保创build一个新的作用域,然后监听对文件input元素所做的更改。 当检测到变化时,将文件对象作为参数向所有祖先范围发送事件(向上)。
在你的控制器中:
$scope.files = []; //listen for the file selected event $scope.$on("fileSelected", function (event, args) { $scope.$apply(function () { //add the file object to the scope's files collection $scope.files.push(args.file); }); });
然后在你的ajax调用中:
data: { model: $scope.model, files: $scope.files }
http://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/
我认为这是angular度file upload:
NG-file upload
轻量级Angular JS指令来上传文件。
这是DEMO page.Features
- 支持上传进度,正在进行的取消/中止上传,文件拖放(html5),目录拖放(webkit),CORS,PUT(html5)/ POST方法,文件types和大小的validation,显示所选图像的预览/audio/video。
- 使用Flash polyfill FileAPI跨浏览器file upload和FileReader(HTML5和非HTML5)。 上传文件前允许客户端validation/修改
- 直接上传到数据库服务CouchDB,imgur等…与文件的内容types使用Upload.http()。 这将启用angular度http POST / PUT请求的进度事件。
- 单独的shim文件,FileAPI文件是非HTML5代码的需求加载的意思是没有额外的负载/代码,如果你只是需要HTML5的支持。
- 轻量级使用常规的$ http上传(非HTML5浏览器的垫片),所以所有angular$ httpfunction都可用
您的文件和json数据同时上传。
// FIRST SOLUTION var _post = function (file, jsonData) { $http({ url: your url, method: "POST", headers: { 'Content-Type': undefined }, transformRequest: function (data) { var formData = new FormData(); formData.append("model", angular.toJson(data.model)); formData.append("file", data.files); return formData; }, data: { model: jsonData, files: file } }).then(function (response) { ; }); } // END OF FIRST SOLUTION // SECOND SOLUTION // İf you can add plural file and İf above code give an error. // You can try following code var _post = function (file, jsonData) { $http({ url: your url, method: "POST", headers: { 'Content-Type': undefined }, transformRequest: function (data) { var formData = new FormData(); formData.append("model", angular.toJson(data.model)); for (var i = 0; i < data.files.length; i++) { // add each file to // the form data and iteratively name them formData.append("file" + i, data.files[i]); } return formData; }, data: { model: jsonData, files: file } }).then(function (response) { ; }); } // END OF SECOND SOLUTION
你可以使用一个安全快速的FormData
对象:
// Store the file object when input field is changed $scope.contentChanged = function(event){ if (!event.files.length) return null; $scope.content = new FormData(); $scope.content.append('fileUpload', event.files[0]); $scope.$apply(); } // Upload the file over HTTP $scope.upload = function(){ $http({ method: 'POST', url: '/remote/url', headers: {'Content-Type': undefined }, data: $scope.content, }).success(function(response) { // Uploading complete console.log('Request finished', response); }); }
http://jsfiddle.net/vishalvasani/4hqVu/在Chrome和IE中工作正常(如果你在后台图像更新一点CSS)。; 这用于更新进度栏:
scope.progress = Math.round(evt.loaded * 100 / evt.total)
但是在FireFox中,angular度的[百分比]数据不会在DOM中成功更新,尽pipe文件正在成功上传。
您可以考虑IaaSfile upload,如Uploadcare 。 有一个Angular包: https : //github.com/uploadcare/angular-uploadcare
从技术上讲,它是作为一个指令实现的,提供了不同的上传选项,以及在widget中上传图片的操作:
<uploadcare-widget ng-model="object.image.info.uuid" data-public-key="YOURKEYHERE" data-locale="en" data-tabs="file url" data-images-only="true" data-path-value="true" data-preview-step="true" data-clearable="true" data-multiple="false" data-crop="400:200" on-upload-complete="onUCUploadComplete(info)" on-widget-ready="onUCWidgetReady(widget)" value="{{ object.image.info.cdnUrl }}" />
更多的configuration选项来玩: https : //uploadcare.com/widget/configure/
我知道这是一个迟到的条目,但我已经创build了一个简单的上传指令。 你可以在任何时候工作!
<input type="file" multiple ng-simple-upload web-api-url="/api/Upload" callback-fn="myCallback" />
ng-simple-upload在Github 上更多地使用Web API的例子。
<input type=file>
元素默认不使用ng-model指令 。 它需要一个自定义指令 :
与ng-model
一起使用的“files-input”指令的工作演示1
angular.module("app",[]); angular.module("app").directive("filesInput", 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="angular/angular.js"></script> <body ng-app="app"> <h1>AngularJS Input `type=file` Demo</h1> <input type="file" files-input ng-model="fileList" multiple> <h2>Files</h2> <div ng-repeat="file in fileList"> {{file.name}} </div> </body>
这应该是更新/评论@ jquery-guru的答案,但因为我没有足够的代表它会去这里。 它修复了现在由代码生成的错误。
https://jsfiddle.net/vzhrqotw/
这个变化基本上是:
FileUploadCtrl.$inject = ['$scope'] function FileUploadCtrl(scope) {
至:
app.controller('FileUploadCtrl', function($scope) {
随意移动到一个更合适的位置,如果需要的话。
我已经阅读了所有的线程,HTML5 API解决scheme看起来是最好的。 但它改变我的二进制文件,以我没有调查的方式腐蚀他们。 完美的解决scheme是:
HTML:
<input type="file" id="msds" ng-model="msds" name="msds"/> <button ng-click="msds_update()"> Upload </button>
JS:
msds_update = function() { var f = document.getElementById('msds').files[0], r = new FileReader(); r.onloadend = function(e) { var data = e.target.result; console.log(data); var fd = new FormData(); fd.append('file', data); fd.append('file_name', f.name); $http.post('server_handler.php', fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }) .success(function(){ console.log('success'); }) .error(function(){ console.log('error'); }); }; r.readAsDataURL(f); }
服务器端(PHP):
$file_content = $_POST['file']; $file_content = substr($file_content, strlen('data:text/plain;base64,')); $file_content = base64_decode($file_content);
以上接受的答案不是浏览器兼容的。 如果有人遇到兼容性问题,请尝试一下。
小提琴
查看代码
<div ng-controller="MyCtrl"> <input type="file" id="file" name="file"/> <br> <button ng-click="add()">Add</button> <p>{{data}}</p> </div>
控制器代码
var myApp = angular.module('myApp',[]); function MyCtrl($scope) { $scope.data = 'none'; $scope.add = function(){ var f = document.getElementById('file').files[0], r = new FileReader(); r.onloadend = function(e){ var binary = ""; var bytes = new Uint8Array(e.target.result); var length = bytes.byteLength; for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); } $scope.data = (binary).toString(); alert($scope.data); } r.readAsArrayBuffer(f); } }
HTML
<input type="file" id="file" name='file' onchange="angular.element(this).scope().profileimage(this)" />
将“profileimage()”方法添加到您的控制器
$scope.profileimage = function(selectimage) { console.log(selectimage.files[0]); var selectfile=selectimage.files[0]; r = new FileReader(); r.onloadend = function (e) { debugger; var data = e.target.result; } r.readAsBinaryString(selectfile); }
用简单的话来说
在Html中 –仅添加以下代码
<form name="upload" class="form" data-ng-submit="addFile()"> <input type="file" name="file" multiple onchange="angular.element(this).scope().uploadedFile(this)" /> <button type="submit">Upload </button> </form>
在控制器中 – 当你点击“上传文件button”时,这个function被调用。 它会上传文件。 你可以安慰它。
$scope.uploadedFile = function(element) { $scope.$apply(function($scope) { $scope.files = element.files; }); }
在控制器中添加更多 – 将代码添加到函数中。 当你点击“使用api(POST)”button时,这个函数被调用。 它会发送文件(上传)和表单数据到后端。
var url = httpURL + "/reporttojson" var files=$scope.files; for ( var i = 0; i < files.length; i++) { var fd = new FormData(); angular.forEach(files,function(file){ fd.append('file',file); }); var data ={ msg : message, sub : sub, sendMail: sendMail, selectUsersAcknowledge:false }; fd.append("data", JSON.stringify(data)); $http.post(url, fd, { withCredentials : false, headers : { 'Content-Type' : undefined }, transformRequest : angular.identity }).success(function(data) { toastr.success("Notification sent successfully","",{timeOut: 2000}); $scope.removereport() $timeout(function() { location.reload(); }, 1000); }).error(function(data) { toastr.success("Error in Sending Notification","",{timeOut: 2000}); $scope.removereport() }); }
在这种情况下..我添加下面的代码作为表单数据
var data ={ msg : message, sub : sub, sendMail: sendMail, selectUsersAcknowledge:false };
<form id="csv_file_form" ng-submit="submit_import_csv()" method="POST" enctype="multipart/form-data"> <input ng-model='file' type="file"/> <input type="submit" value='Submit'/> </form>
在angularJS控制器中
$scope.submit_import_csv = function(){ var formData = new FormData(document.getElementById("csv_file_form")); console.log(formData); $.ajax({ url: "import", type: 'POST', data: formData, mimeType:"multipart/form-data", contentType: false, cache: false, processData:false, success: function(result, textStatus, jqXHR) { console.log(result); } }); return false; }
app.directive('ngUpload', function () { return { restrict: 'A', link: function (scope, element, attrs) { var options = {}; options.enableControls = attrs['uploadOptionsEnableControls']; // get scope function to execute on successful form upload if (attrs['ngUpload']) { element.attr("target", "upload_iframe"); element.attr("method", "post"); // Append a timestamp field to the url to prevent browser caching results element.attr("action", element.attr("action") + "?_t=" + new Date().getTime()); element.attr("enctype", "multipart/form-data"); element.attr("encoding", "multipart/form-data"); // Retrieve the callback function var fn = attrs['ngUpload'].split('(')[0]; var callbackFn = scope.$eval(fn); if (callbackFn == null || callbackFn == undefined || !angular.isFunction(callbackFn)) { var message = "The expression on the ngUpload directive does not point to a valid function."; // console.error(message); throw message + "\n"; } // Helper function to create new i frame for each form submission var addNewDisposableIframe = function (submitControl) { // create a new iframe var iframe = $("<iframe id='upload_iframe' name='upload_iframe' border='0' width='0' height='0' style='width: 0px; height: 0px; border: none; display: none' />"); // attach function to load event of the iframe iframe.bind('load', function () { // get content - requires jQuery var content = iframe.contents().find('body').text(); // execute the upload response function in the active scope scope.$apply(function () { callbackFn(content, content !== "" /* upload completed */); }); // remove iframe if (content != "") // Fixes a bug in Google Chrome that dispose the iframe before content is ready. setTimeout(function () { iframe.remove(); }, 250); submitControl.attr('disabled', null); submitControl.attr('title', 'Click to start upload.'); }); // add the new iframe to application element.parent().append(iframe); }; // 1) get the upload submit control(s) on the form (submitters must be decorated with the 'ng-upload-submit' class) // 2) attach a handler to the controls' click event $('.upload-submit', element).click( function () { addNewDisposableIframe($(this) /* pass the submit control */); scope.$apply(function () { callbackFn("Please wait...", false /* upload not completed */); }); var enabled = true; if (options.enableControls === null || options.enableControls === undefined || options.enableControls.length >= 0) { // disable the submit control on click $(this).attr('disabled', 'disabled'); enabled = false; } $(this).attr('title', (enabled ? '[ENABLED]: ' : '[DISABLED]: ') + 'Uploading, please wait...'); // submit the form $(element).submit(); } ).attr('title', 'Click to start upload.'); } else alert("No callback function found on the ngUpload directive."); } }; }); <form class="form form-inline" name="uploadForm" id="uploadForm" ng-upload="uploadForm12" action="rest/uploadHelpFile" method="post" enctype="multipart/form-data" style="margin-top: 3px;margin-left: 6px"> <button type="submit" id="mbUploadBtn" class="upload-submit" ng-hide="true"></button> </form> @RequestMapping(value = "/uploadHelpFile", method = RequestMethod.POST) public @ResponseBody String uploadHelpFile(@RequestParam(value = "file") CommonsMultipartFile[] file,@RequestParam(value = "fileName") String fileName,@RequestParam(value = "helpFileType") String helpFileType,@RequestParam(value = "helpFileName") String helpFileName) { }