Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
ng-file-upload
Advanced tools
An AngularJS directive for file upload using HTML5 with FileAPI polyfill for unsupported browsers
Lightweight Angular directive to upload files.
See the DEMO page.
Migration notes: version 3.0.x version 3.1.x version 3.2.x version 4.x.x version 5.x.x version 6.x.x version 6.2.x version 7.x.x
Ask questions on StackOverflow under the ng-file-upload tag.
For bug report or feature request please search through existing issues first then open a new one here. For faster response provide steps to reprodce/versions with a jsfiddle from here. Need paid support contact me.
Contributions are always welcome. If you like this plugin give it a thumbs up at ngmodules.
Table of Content:
ng-required
support.Upload.$http()
bower install ng-file-upload-shim --save
(for non html5 suppport)bower install ng-file-upload --save
PM> Install-Package angular-file-upload
(thanks to Georgios Diamantopoulos)npm install ng-file-upload
<script src="angular(.min).js"></script>
<script src="ng-file-upload-shim(.min).js"></script> <!-- for no html5 browsers support -->
<script src="ng-file-upload(.min).js"></script>
###Sample: jsfiddle http://jsfiddle.net/j312a26n/
<script src="angular.min.js"></script>
<!-- shim is needed to support non-HTML5 FormData browsers (IE8-9)-->
<script src="ng-file-upload-shim.min.js"></script>
<script src="ng-file-upload.min.js"></script>
<form ng-app="fileUpload" ng-controller="MyCtrl" name="form">
watching model:
<div class="button" ngf-select ng-model="file">Upload using model $watch</div>
<div class="button" ngf-select ng-model="files" ngf-multiple="true" ngf-pattern="'image/*" accept="image/*">Upload multiple images using model $watch</div>
<div class="button" ngf-select ngf-change="upload($file)">Upload on file change</div>
<div class="button" ngf-select ngf-change="upload($files)" ngf-multiple="true" ngf-max-size="'2M'">Upload multiple with size limitation</div>
Drop File:
<div ngf-drop ng-model="files" class="drop-box"
ngf-drag-over-class="dragover" ngf-multiple="true" ngf-allow-dir="true"
ngf-pattern="'image/*,application/pdf'">Drop Images or PDFs files here</div>
<div ngf-no-file-drop>File Drag/Drop is not supported for this browser</div>
Image thumbnail: <img ngf-src="file || '/thumb.jpg'">
Audio preview: <audio controls ngf-src="file"></audio>
Video preview: <video controls ngf-src="file"></video>
</div>
Javascript code:
//inject directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', function ($scope, Upload) {
$scope.$watch('file', function (file) {
if (!file.$error) {
$scope.upload($scope.file);
}
});
/* optional: set default directive values */
//Upload.setDefaults( {ngf-keep:false ngf-accept:'image/*', ...} );
$scope.upload = function (file) {
Upload.upload({
url: 'upload/url',
fields: {'username': $scope.username},
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
}).error(function (data, status, headers, config) {
console.log('error status: ' + status);
})
};
}]);
<button|div|input type="file"|ngf-select|...
*ngf-select="boolean" or "upload($files, $file)" // default true, enables file select directive
// or could be a function same as ngf-change
ng-model="myFiles" // binds the selected file or files to the scope model
// could be an array or single file depending on ngf-multiple and ngf-keep values.
ng-disabled="boolean" // disables this element
ngf-change="upload($files, $file, $event, $rejectedFiles)" // called when files are selected or removed
ngf-multiple="boolean" // default false, allows selecting multiple files
ngf-capture="'camera'" or "'other'" // allows mobile devices to capture using camera
accept="image/*" // standard HTML accept attribute for the browser specific popup window filtering
ngf-keep="boolean" // default false, keep the previous ng-model files and append the new files
ngf-keep-distinct="boolean" // default false, if ngf-keep is set, removes duplicate selected files
//validations:
ngf-pattern="'.pdf,.jpg,video/*'" // comma separated wildcard to filter file names and types allowed
// validate error name: pattern
ngf-min-size, ngf-max-size="100" in bytes or "'10KB'" or "'10MB'" or "'10GB'"
// validate as form.file.$error.maxSize=true and file.$error='maxSize'
ngf-min-heigh, ngf-max-heigh, ngf-min-width, ngf-max-width="1000" in pixels
// validate error name: maxHeight
ngf-min-duration, ngf-max-duration="100.5" in seconds or "'10s'" or "'10m'" or "'10h'"
// validate error name: maxDuration
ngf-validate="{size: {min: 10, max: '20MB'}, width: {min: 100, max:10000},
height: {min: 100, max: 300}, duration: {min: '10s', max: '5m'}, pattern: '.jpg'}"
shorthand form for above validations in one place.
ngf-validate-fn="validate($file)" // custom validation function, return boolean or string containing the error.
// validate error name: validateFn
ngf-validate-async-fn="validate($file)" // custom validation function, return a promise that resolve to
// boolean or string containing the error. validate error name: validateAsyncFn
ngf-validate-later="boolean" (experimental) // default false, if true model will be set and change will be called before validation
>Upload</button>
All attributes are optional except ngf-drop and one of ng-model or ngf-change.
<div|button|ngf-drop|...
*ngf-drop="boolean" or "upload($files, $file)" // default true, enables file drop directive
// or could be a function same as ngf-change
ng-model="myFiles" // binds the dropped file or files to the scope model
// could be an array or single file depending on ngf-multiple and ngf-keep values.
ng-disabled="boolean" // disables this element
ngf-change="fileDropped($files, $file, $event, $rejectedFiles)" //called when files being dropped
ngf-multiple="boolean" // default false, allows selecting multiple files.
ngf-allow-dir="boolean" // default true, allow dropping files only for Chrome webkit browser
ngf-drag-over-class="{accept:'acceptClass', reject:'rejectClass', delay:100}" or "myDragOverClass" or
"calcDragOverClass($event)"
// drag over css class behaviour. could be a string, a function returning class name
// or a json object {accept: 'c1', reject: 'c2', delay:10}. default "dragover".
// accept/reject class only works in Chrome validating only the file mime type
// against ngf-pattern
ngf-drop-available="dropSupported" // set the value of scope model to true or false based on file
// drag&drop support for this browser
ngf-stop-propagation="boolean" // default false, whether to propagate drag/drop events.
ngf-hide-on-drop-not-available="boolean" // default false, hides element if file drag&drop is not
//validations:
same as ngf-select see above
supported
>
Drop files here
</div>
<div|... ngf-no-file-drop>File Drag/drop is not supported</div>
<img|audio|video
ngf-src="file" //To preview the selected file, sets src attribute to the file data url.
ngf-background="file" //sets background-image style to the file data url.
ngf-no-object-url="true or false" // see #887 to force base64 url generation instead of object url. Default false
>
var upload = Upload.upload({
*url: 'server/upload/url', // upload.php script, node.js route, or servlet url
*file: file, // single file or an array of files (array is for html5 only)
method: 'POST' or 'PUT'(html5), default POST,
headers: {'Authorization': 'xxx'}, // only for html5
fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...], // to modify the name of the file(s)
/*
file formData name ('Content-Disposition'), server side request form name could be
an array of names for multiple files (html5). Default is 'file' */
fileFormDataName: 'myFile' or ['file[0]', 'file[1]', ...],
/*
map of extra form data fields to send along with file. each field will be sent as a form field.
The values are converted to json string or jsob blob or nested form depending on 'sendFieldsAs' option. */
fields: {key: $scope.myValue, ...},
/*
default is 'json', sends each field as json string plain text content type, 'json-blob' sends object fields
as a blob object with content type 'application/json', 'form' sends fields as nested form fields. see #784 */
sendFieldsAs: json|json-blob|form,
/* customize how data is added to the formData. See #40#issuecomment-28612000 for sample code. */
formDataAppender: function(formData, key, val){},
/*
data will be sent as a separate form data field called "data".*/
data: {}.
withCredentials: true|false,
... and all other angular $http() options could be used here.
}).progress(function(evt) {
console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total) + '% file :'+ evt.config.file.name);
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);
}).error(function(data, status, headers, config) {
// handle error
}).xhr(function(xhr){
//access or attach event listeners to the underlying XMLHttpRequest
xhr.upload.addEventListener(...)
});
/* return $http promise then,catch or finally.
Note that this promise does NOT have progress, abort or xhr functions */
var promise = upload.then(success, error, progress);
upload.catch(errorCallback);
upload.finally(callback, notifyCallback);
/* cancel/abort the upload in progress. */
upload.abort();
/* 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 enable progress for regualr angular $http() post/put requests.
*/
Upload.http({
url: '/server/upload/url',
headers : {
'Content-Type': file.type
},
data: file
})
/* Set the default values for ngf-select and ngf-drop directives*/
Upload.setDefaults({ngfMinSize: 20000, ngfMaxSize:20000000, ...})
/* Convert the file to base64 data url*/
Upload.dataUrl(file, disallowObjectUrl).then(function(url){...});
/* Get image file dimensions*/
Upload.imageDimensions(file).then(function(dimensions){console.log(dimensions.widht, dimensions.height);});
/* Geet audio/video duration*/
Upload.mediaDuration(file).then(function(durationInSeconds){...});
ng-model The model value will be a single file instead of an array if all of the followings are true:
ngf-multiple
is not set or is resolved to false.multiple
attribute is not set on the elementngf-keep
is not set or is resolved to false.validation
When any of the validation directives specified the form validation will take place and you can access the value of the validation using myForm.myFileInputName.$error.<validate error name>
for example form.file.$error.pattern
. If multiple file selection is allowed you can find the error of each individual file with file.$error
and description of it file.$errorParam
.
So before uploading you can check if the file is valid by !file.$error
.
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[]
).
Non-html5 browsers due to flash limitation will still upload array of files one by one in a separate request. You should iterate over files and send them one by one if you want cross browser solution.
Upload.http(): This is equivalent to angular $http() but allow you to listen to the progress event for HTML5 browsers.
drag and drop styling: For file drag and drop, ngf-drag-over-class
could be used to style the drop zone. It can be a function that returns a class name based on the $event. Default is "dragover" string.
Only in chrome It could be a json object {accept: 'a', 'reject': 'r', delay: 10}
that specify the class name for the accepted or rejected drag overs. The validation ngf-accept
could only check the file type since that is the only property of the file that is reported by the browser on drag. So you cannot validate the file size or name on drag. There is also some limitation on some file types which are not reported by Chrome.
delay
param is there to fix css3 transition issues from dragging over/out/over #277.
ngf-reset-on-click and ngf-reset-model-on-click: These two options are for testing purposes or rare cases, be aware that they might make the file select behave differently on different browsers. By default since there is no cross-browser way to detect cancel on the file popup everytime you click on the file select it would create a new element and click on that and the model value will be reset to empty. This would also allow selecting the same file again which normally will not trigger a change event. Setting this to false would not create a new element, and browsers will behave differently when the user cancels the popup, for example for chrome you would receive a change event with empty files but in FireFox there will be no event fired. This could be helpful in some rare cases or for testing when you want to keep the original elements without replacing them. Setting ngf-reset-model-on-click will not reset the model when you click on the file select, that would make reseting model when the user cancels the select popup impossible in some browsers.
ng-model-rejected:
You can find the reason for rejection using file.$error
which would be one of these values accept
, validate
, size.min
, size.max
, width.min
, width.max
, height.min
, height.max
, duration.min
, duration.max
. Extra information about the error is available through file.$errorParam
which for example could be the maximum file limit in case the error is size.max
.
accept
is for the case the file doesn't match the ngf-accept
or ngf-validate.accept
criteria.
validate
is for the case when the ngf-validate is a custom function and returns false or non empty string for that file.
Upload.setDefaults():
If you have many file selects or drops you can set the default values for the directives by calling Upload.setDefaults(options)
. options
would be a json object with directive names in camelcase and their default values.
For browsers not supporting HTML5 FormData (IE8, IE9, ...) FileAPI module is used.
Note: You need Flash installed on your browser since FileAPI
uses Flash to upload files.
These two files FileAPI.min.js
, FileAPI.flash.swf
will be loaded by the module on demand (no need to be included in the html) if the browser does not supports HTML5 FormData to avoid extra load for HTML5 browsers.
You can place these two files beside angular-file-upload-shim(.min).js
on your server to be loaded automatically from the same path or you can specify the path to those files if they are in a different path using the following script:
<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
//noContentTimeout: 10000 (see #528)
}
</script>
<script src="angular-file-upload-shim.min.js"></script>...
Old browsers known issues:
204 'No Content'
. So if you have access to your server upload code at least return a character in the response for the status code to work properly.PUT
requests. #261##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>
The demo page has an option to upload to S3. Here is a sample config options:
Upload.upload({
url: 'https://angular-file-upload.s3.amazonaws.com/', //S3 upload url including bucket name
method: 'POST',
fields : {
key: file.name, // the key to store the file on S3, could be file name or customized
AWSAccessKeyId: <YOUR AWS AccessKey Id>,
acl: 'private', // sets the access to the uploaded file in the bucket: private or public
policy: $scope.policy, // base64-encoded json policy (see article below)
signature: $scope.signature, // base64-encoded signature based on policy string (see article below)
"Content-Type": file.type != '' ? file.type : 'application/octet-stream', // content type of the file (NotEmpty)
filename: file.name // this is needed for Flash polyfill IE8-9
},
file: file,
});
This article explains more about these fields and provides instructions on how to generate the policy and signature using a server side tool. These two values are generated from the json policy document which looks like this:
{"expiration": "2020-01-01T00:00:00Z",
"conditions": [
{"bucket": "angular-file-upload"},
["starts-with", "$key", ""],
{"acl": "private"},
["starts-with", "$Content-Type", ""],
["starts-with", "$filename", ""],
["content-length-range", 0, 524288000]
]
}
The demo page provide a helper tool to generate the policy and signature from you from the json policy document. Note: Please use https protocol to access demo page if you are using this tool to generate signature and policy to protect your aws secret key which should never be shared.
Make sure that you provide upload and CORS post to your bucket at AWS -> S3 -> bucket name -> Properties -> Edit bucket policy and Edit CORS Configuration. Samples of these two files:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "UploadFile",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxx:user/xxx"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::angular-file-upload/*"
},
{
"Sid": "crossdomainAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::angular-file-upload/crossdomain.xml"
}
]
}
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>http://angular-file-upload.appspot.com</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
For IE8-9 flash polyfill you need to have a crossdomain.xml file at the root of you S3 bucket. Make sure the content-type of crossdomain.xml is text/xml and you provide read access to this file in your bucket policy.
You can also have a look at https://github.com/nukulb/s3-angular-file-upload for another example with this fix.
FAQs
An AngularJS directive for file upload using HTML5 with FileAPI polyfill for unsupported browsers
The npm package ng-file-upload receives a total of 41,971 weekly downloads. As such, ng-file-upload popularity was classified as popular.
We found that ng-file-upload demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.