Lightweight Angular JS directive to upload files.
See the DEMO page
Table of Content:
- File upload for
HTML5
andnon-HTML5
browsers with Flash polyfill FileAPI. Allows client side validation before uploading the file - Uses regular
$http
to upload (with shim for non-HTML5 browsers) so all angular$http
features are available - Supports upload progress
- Supports cancel/abort upload while in progress
- Supports File drag and drop (HTML5 only)
- Supports Directory drag and drop (webkit only)
- Supports CORS
- All
non-HTML5
code is in a separate shim file and could be easily removed if you only supportsHTML5
. (html5-shim.js is needed forprogress
event though) - Flash
FileAPI
will be loaded on demand fornon-HTML5
FormData browsers so no extra load forHTML5
browsers. $upload
method can be configured to be eitherPOST
orPUT
for HTML5 browsers.$upload.http()
enables progress event for angular httpPOST
/PUT
requests. You can upload file content with theContent-Type
of the file to CouchDB, imgur, etc... forHTML5
FileReader
browsers. See #88(comment) for discussion and usage.
HTML:
<!-- shim is needed to support upload progress/abort for HTML5 and non-HTML5 FormData browsers.-->
<!-- angular-file-upload-html5-shim.js could be used instead of angular-file-upload-shim if your app
targets HTML5 browsers only (not IE8-9) -->
<!-- Note: shim.js MUST BE PLACED BEFORE angular.js and angular-file-upload.js AFTER angular.js-->
<script src="angular-file-upload-shim.min.js"></script>
<script src="angular.min.js"></script>
<script src="angular-file-upload.min.js"></script>
<div ng-controller="MyCtrl">
<input type="text" ng-model="myModelObj">
<input type="file" ng-file-select="onFileSelect($files)">
<input type="file" ng-file-select="onFileSelect($files)" multiple accept="image/*">
<div class="button" ng-file-select="onFileSelect($files)" data-multiple="true"></div>
<div ng-file-drop="onFileSelect($files)" ng-file-drag-over-class="optional-css-class-name-or-function"
ng-show="dropSupported">drop files here</div>
<div ng-file-drop-available="dropSupported=true"
ng-show="!dropSupported">HTML5 Drop File is not supported!</div>
<button ng-click="upload.abort()">Cancel Upload</button>
</div>
JS:
//inject angular file upload directives and service.
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];
$scope.upload = $upload.upload({
url: 'server/upload/url', //upload.php script, node.js route, or servlet url
//method: 'POST' or 'PUT',
//headers: {'header-key': 'header-value'},
//withCredentials: true,
data: {myObj: $scope.myModelObj},
file: file, // or list of files ($files) for html5 only
//fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...] // to modify the name of the file(s)
// customize file formData name ('Content-Disposition'), server side file variable name.
//fileFormDataName: myFile, //or a list of names for multiple files (html5). Default is 'file'
// customize how data is added to formData. See #40#issuecomment-28612000 for sample code
//formDataAppender: function(formData, key, val){}
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
//.error(...)
//.then(success, error, progress);
// access or attach event listeners to the underlying XMLHttpRequest.
//.xhr(function(xhr){xhr.upload.addEventListener(...)})
}
/* alternative way of uploading, send the file binary with the file's content-type.
Could be used to upload files to CouchDB, imgur, etc... html5 FileReader is needed.
It could also be used to monitor the progress of a normal http post/put request with large data*/
// $scope.upload = $upload.http({...}) see 88#issuecomment-31366487 for sample code.
};
}];
Order of scripts: angular-file-upload-shim.js
must be loaded before angular.js
and is only needed if you are supporting non-HTML5 FormData browsers or you need to support upload progress or cancel.
Upload multiple files: Only for HTML5 FormData browsers (not IE8-9) if you pass an array of files to file
option it will upload all of them together in one request. In this case the fileFormDataName
could be an array of names or a single string. For Rails or depending on your server append square brackets to the end (i.e. file[]
).
If you want a cross browser approach you need to iterate through files and upload them one by one like the code above. This is due to the limitation of Flash file upload.
$upload.http(): You can also use $upload.http()
to send the file binary or any data to the server while being able to listen to progress event. See #88 for more details.
This equivalent to angular $http() but allow you to listen to progress event for HTML5 browsers.
Rails progress event: If your server is Rails and Apache you may need to modify server configurations for the server to support upload progress. See #207
drag and drop styling: For file drag and drop, ng-file-drag-over-class
can be a function that returns a class name based on the $event. See the demo for a sample. If the attribute is not specified by default the element will have "dragover" class on drag over which could be used to style the drop zone.
You can also specify ng-file-drag-over-delay
to fix css3 transition issues from dragging over/out/over #277.
For browsers not supporting HTML5 FormData (IE8, IE9, ...) FileAPI module is used.
For these browsers these two files are needed: FileAPI.min.js
, FileAPI.flash.swf
which will be loaded if the browser does not supports HTML5 FormData (no extra load for HTML5 browsers).
Note: Flash needs to be installed on the client browser since FileAPI
uses Flash to upload files.
CORS: To enable CORS
You can put these two files beside angular-file-upload-shim(.min).js
on your server to be loaded automatically on demand or optionally you can use the following script to set the FileAPI load path if they are not at the same location:
<script>
//optional need to be loaded before angular-file-upload-shim(.min).js
FileAPI = {
//only one of jsPath or jsUrl.
jsPath: '/js/FileAPI.min.js/folder/',
jsUrl: 'yourcdn.com/js/FileAPI.min.js',
//only one of staticPath or flashUrl.
staticPath: '/flash/FileAPI.flash.swf/folder/',
flashUrl: 'yourcdn.com/js/FileAPI.flash.swf',
//forceLoad: true, html5: false //to debug flash in HTML5 browsers
}
</script>
<script src="angular-file-upload-shim.min.js"></script>...
Old browsers known issues:
- Because of a Flash limitation/bug the server needs to send a response body in order for the success and error callbacks to work properly. See 163#issuecomment
- Custom headers will not work due to a Flash limitation #111 #224 #129
- Due to Flash bug #92 Server HTTP error code 400 will be returned as 200 to the client. So avoid returning 400 on your server side for upload response otherwise it will be treated as a success response on the client side.
##Server Side ####CORS To support CORS upload your server needs to allow cross domain requests. You can achive that by having a filter or interceptor on your upload file server to add CORS headers to the response similar to this: (sample java code)
httpResp.setHeader("Access-Control-Allow-Methods", "POST, PUT, OPTIONS");
httpResp.setHeader("Access-Control-Allow-Origin", "your.other.server.com");
httpResp.setHeader("Access-Control-Allow-Headers", "Content-Type"));
For non-HTML5 IE8-9 browsers you would also need a crossdomain.xml
file at the root of your server to allow CORS for flash:
(sample xml)
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="angular-file-upload.appspot.com"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>
####Samples
- Amazon S3 Upload: nukulb has provided an example here https://github.com/hubba/s3-angular-file-upload
- Node.js: Sample wiki page provided by chovy
- Java/GAE: You can find the sample server code in Java/GAE here
Download latest release from here or if you are using bower
#notice 'ng' at the beginning of the module name not 'angular'
bower install ng-file-upload
Make sure to load the scripts in your html file exactly in this order as described in the Usage:
<script src="angular-file-upload-shim(.min).js"></script>
<script src="angular(.min).js"></script>
<script src="angular-file-upload(.min).js"></script>
Or for yeoman with bower automatic include:
bower install ng-file-upload -save
bower install ng-file-upload-shim -save
bower.json
{
"dependencies": [..., "ng-file-upload-shim", "angularjs", "ng-file-upload", ...],
}
For questions, bug reports, and feature request please search through existing issue and if you don't find and answer open a new one here. If you need support send me an email to set up a session through HackHands. You can also contact me for any non public concerns.
If you like the plugin give it a thumbs up at http://ngmodules.org/modules/angular-file-upload,
also get me a cup of tea so I add features and fixes faster.