Coder Social home page Coder Social logo

danialfarid / ng-file-upload Goto Github PK

View Code? Open in Web Editor NEW
7.9K 274.0 1.6K 55.52 MB

Lightweight Angular directive to upload files with optional FileAPI shim for cross browser support

License: MIT License

JavaScript 98.95% HTML 0.32% Shell 0.61% Batchfile 0.12%

ng-file-upload's Introduction

npm version Downloads Issue Stats Issue Stats
PayPayl donate button Gratipay donate button

ng-file-upload

Lightweight Angular directive to upload files.

See the DEMO page. Reference docs here

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.0.x version 7.2.x version 8.0.x version 9.0.x version 10.0.x version 11.0.x version 12.0.x version 12.1.x version 12.2.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 reproduce/versions with a jsfiddle link. If you need support for your company contact me.
If you like this plugin give it a thumbs up at ngmodules or get me a cup of tea . Contributions are welcomed.

Table of Content:

Features

  • file upload progress, cancel/abort
  • file drag and drop (html5 only)
  • image paste from clipboard and drag and drop from browser pages (html5 only).
  • image resize and center crop (native) and user controlled crop through ngImgCrop. See crop sample (html5 only)
  • orientation fix for jpeg image files with exif orientation data
  • resumable uploads: pause/resume upload (html5 only)
  • native validation support for file type/size, image width/height/aspect ratio, video/audio duration, and ng-required with pluggable custom sync or async validations.
  • show thumbnail or preview of selected images/audio/videos
  • supports CORS and direct upload of file's binary data using Upload.$http()
  • plenty of sample server side code, available on nuget
  • on demand flash FileAPI shim loading no extra load for html5 browsers.
  • HTML5 FileReader.readAsDataURL shim for IE8-9
  • available on npm, bower, meteor, nuget

Install

  • Manual: download latest from here
  • Bower:
    • bower install ng-file-upload-shim --save(for non html5 suppport)
    • bower install ng-file-upload --save
  • NuGet: PM> Install-Package angular-file-upload (thanks to Georgios Diamantopoulos)
  • NPM: 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>

Usage

Samples:

<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>

Upload on form submit or button click
<form ng-app="fileUpload" ng-controller="MyCtrl" name="form">
  Single Image with validations
  <div class="button" ngf-select ng-model="file" name="file" ngf-pattern="'image/*'"
    ngf-accept="'image/*'" ngf-max-size="20MB" ngf-min-height="100"
    ngf-resize="{width: 100, height: 100}">Select</div>
  Multiple files
  <div class="button" ngf-select ng-model="files" ngf-multiple="true">Select</div>
  Drop files: <div ngf-drop ng-model="files" class="drop-box">Drop</div>
  <button type="submit" ng-click="submit()">submit</button>
</form>

Upload right away after file selection:
<div class="button" ngf-select="upload($file)">Upload on file select</div>
<div class="button" ngf-select="uploadFiles($files)" multiple="multiple">Upload on file select</div>
  Drop File:
<div ngf-drop="uploadFiles($files)" class="drop-box"
  ngf-drag-over-class="'dragover'" ngf-multiple="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-thumbnail="file || '/thumb.jpg'">
Audio preview: <audio controls ngf-src="file"></audio>
Video preview: <video controls ngf-src="file"></video>

Javascript code:

//inject directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);

app.controller('MyCtrl', ['$scope', 'Upload', function ($scope, Upload) {
    // upload later on form submit or something similar
    $scope.submit = function() {
      if ($scope.form.file.$valid && $scope.file) {
        $scope.upload($scope.file);
      }
    };

    // upload on file select or drop
    $scope.upload = function (file) {
        Upload.upload({
            url: 'upload/url',
            data: {file: file, 'username': $scope.username}
        }).then(function (resp) {
            console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data);
        }, function (resp) {
            console.log('Error status: ' + resp.status);
        }, function (evt) {
            var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
            console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
        });
    };
    // for multiple files:
    $scope.uploadFiles = function (files) {
      if (files && files.length) {
        for (var i = 0; i < files.length; i++) {
          Upload.upload({..., data: {file: files[i]}, ...})...;
        }
        // or send them all together for HTML5 browsers:
        Upload.upload({..., data: {file: files}, ...})...;
      }
    }
}]);

Full reference

File select and drop

At least one of the ngf-select or ngf-drop are mandatory for the plugin to link to the element. ngf-select only attributes are marked with * and ngf-drop only attributes are marked with +.

<div|button|input type="file"|ngf-select|ngf-drop...
  ngf-select="" or "upload($files, ...)"  <!-- called when files are selected or cleared -->
  ngf-drop="" or "upload($files, ...)" <!--  called when files being dropped
    You can use ng-model or ngf-change instead of specifying function for ngf-drop and ngf-select
    function parameters are the same as ngf-change -->
  ngf-change="upload($files, $file, $newFiles, $duplicateFiles, $invalidFiles, $event)"
    <!--  called when files are selected, dropped, or cleared -->
  ng-model="myFiles" <!--  binds the valid selected/dropped file or files to the scope model
    could be an array or single file depending on ngf-multiple and ngf-keep values. -->
  ngf-model-options="{updateOn: 'change click drop dropUrl paste', allowInvalid: false, debounce: 0}"
    <!--  updateOn could be used to disable resetting on click, or updating on paste, browser 
    image drop, etc. allowInvalid default is false could allow invalid files in the model
    debouncing will postpone model update (miliseconds). See angular ng-model-options for more details. -->
  ngf-model-invalid="invalidFile(s)" <!--  binds the invalid selected/dropped file or files to this model. -->
  ngf-before-model-change="beforeChange($files, ...)" <!--  called after file select/drop and before
    model change, validation and resize is processed -->
  ng-disabled="boolean" <!--  disables this element -->
  ngf-select-disabled="boolean" <!--  default false, disables file select on this element -->
  ngf-drop-disabled="boolean" <!--  default false, disables file drop on this element -->
  ngf-multiple="boolean" <!--  default false, allows selecting multiple files -->
  ngf-keep="true|false|'distinct'" <!--  default false, keep the previous ng-model files and 
    append the new files. "'distinct'" removes duplicate files
    $newFiles and $duplicateFiles are set in ngf-change/select/drop functions. -->
  ngf-fix-orientation="boolean" <!-- default false, would rotate the jpeg image files that have
    exif orientation data. See #745. Could be a boolean function like shouldFixOrientation($file)
    to decide wethere to fix that file or not. -->

  *ngf-capture="'camera'" or "'other'" <!--  allows mobile devices to capture using camera -->
  *ngf-accept="'image/*'" <!--  standard HTML accept attr, browser specific select popup window -->

  +ngf-allow-dir="boolean" <!--  default true, allow dropping files only for Chrome webkit browser -->
  +ngf-include-dir="boolean" <!-- default false, include directories in the dropped file array.
    You can detect if they are directory or not by checking the type === 'directory'. -->
  +ngf-drag-over-class="{pattern: 'image/*', accept:'acceptClass', reject:'rejectClass', delay:100}"
                    or "'myDragOverClass'" or "calcDragOverClass($event)"
    <!--  default "dragover". drag over css class behaviour. could be a string, a function
    returning class name or a json object.
    accept/reject class only works in Chrome, validating only the file mime type.
    if pattern is not specified ngf-pattern will be used. See following docs for more info. -->
  +ngf-drag="drag($isDragging, $class, $event)" <!--  function called on drag over/leave events.
    $isDragging: boolean true if is dragging over(dragover), false if drag has left (dragleave)
    $class is the class that is being set for the element calculated by ngf-drag-over-class -->
  +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 -->
  +ngf-enable-firefox-paste="boolean" <!--  *experimental* default false, enable firefox image paste 
    by making element contenteditable -->

  ngf-resize="{width: 100, height: 100, quality: .8, type: 'image/jpeg',
               ratio: '1:2', centerCrop: true, pattern='.jpg', restoreExif: false}"
               or resizeOptions() <!--  a function returning a promise which resolves into the options.
    resizes the image to the given width/height or ratio. Quality is optional between 0.1 and 1.0),
    type is optional convert it to the given image type format.
    centerCrop true will center crop the image if it does not fit within the given width/height or ratio.
    centerCrop false (default) will not crop the image and will fit it within the given width/height or ratio
    so the resulting image width (or height) could be less than given width (or height).
    pattern is to resize only the files that their name or type matches the pattern similar to ngf-pattern.
    restoreExif boolean default true, will restore exif info on the resized image. -->
  ngf-resize-if="$width > 1000 || $height > 1000" or "resizeCondition($file, $width, $height)"
    <!--  apply ngf-resize only if this function returns true. To filter specific images to be resized. -->
  ngf-validate-after-resize="boolean" <!--  default false, if true all validation will be run after
    the images are being resized, so any validation error before resize will be ignored. -->

  <!-- validations: -->
  ngf-max-files="10" <!--  maximum number of files allowed to be selected or dropped, validate error name: maxFiles -->
  ngf-pattern="'.pdf,.jpg,video/*,!.jog'" <!--  comma separated wildcard to filter file names and 
    types allowed you can exclude specific files by ! at the beginning. validate error name: pattern -->
  ngf-min-size, ngf-max-size, ngf-max-total-size="100" in bytes or "'10KB'" or "'10MB'" or "'10GB'"
    <!--  validate as form.file.$error.maxSize=true and file.$error='maxSize'
    ngf-max-total-size is for multiple file select and validating the total size of all files. -->
  ngf-min-height, ngf-max-height, ngf-min-width, ngf-max-width="1000" in pixels only images
    <!--  validate error names: minHeight, maxHeight, minWidth, maxWidth -->
  ngf-ratio="8:10,1.6" <!--  list of comma separated valid aspect ratio of images in float or 2:3 format
    validate error name: ratio -->
  ngf-min-ratio, ngf-max-ratio="8:10" <!--  min or max allowed aspect ratio for the image. -->
  ngf-dimensions="$width > 1000 || $height > 1000" or "validateDimension($file, $width, $height)"
    <!--  validate the image dimensions, validate error name: dimensions -->
  ngf-min-duration, ngf-max-duration="100.5" in seconds or "'10s'" or "'10m'" or "'10h'" only audio, video
    <!--  validate error name: maxDuration -->
  ngf-duration="$duration > 1000" or "validateDuration($file, $duration)"
    <!--  validate the media duration, validate error name: duration -->

  ngf-validate="{size: {min: 10, max: '20MB'}, width: {min: 100, max:10000}, height: {min: 100, max: 300}
                ratio: '2x1', 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-force="boolean" <!--  default false, if true file.$error will be set if 
    the dimension or duration values for validations cannot be calculated for example 
    image load error or unsupported video by the browser. by default it would assume the file 
    is valid if the duration or dimension cannot be calculated by the browser. -->
  ngf-ignore-invalid="'pattern maxSize'" <!--  ignore the files that fail the specified validations. 
    They will just be ignored and will not show up in ngf-model-invalid or make the form invalid.
    space separated list of validate error names. -->
  ngf-run-all-validations="boolean" <!--  default false. Runs all the specified validate directives. 
    By default once a validation fails for a file it would stop running other validations for that file. -->

>Upload/Drop</div>

<div|... ngf-no-file-drop>File Drag/drop is not supported</div>

<!--  filter to convert the file to base64 data url. -->
<a href="file | ngfDataUrl">image</a>

File preview

<img|audio|video|div
  *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-resize="{width: 20, height: 20, quality: 0.9}" <!--  only for image resizes the image 
    before setting it as src or background image. quality is optional. -->
  ngf-no-object-url="true or false" <!--  see #887 to force base64 url generation instead of 
    object url. Default false -->
>

<div|span|...
 *ngf-thumbnail="file" <!-- Generates a thumbnail version of the image file -->
 ngf-size="{width: 20, height: 20, quality: 0.9}" the image will be resized to this size
        <!--  if not specified will be resized to this element`s client width and height. -->
 ngf-as-background="boolean" <!-- if true it will set the background image style instead of src attribute. -->
>

Upload service:

var upload = Upload.upload({
  *url: 'server/upload/url', // upload.php script, node.js route, or servlet url
  /*
  Specify the file and optional data to be sent to the server.
  Each field including nested objects will be sent as a form data multipart.
  Samples: {pic: file, username: username}
    {files: files, otherInfo: {id: id, person: person,...}} multiple files (html5)
    {profiles: {[{pic: file1, username: username1}, {pic: file2, username: username2}]} nested array multiple files (html5)
    {file: file, info: Upload.json({id: id, name: name, ...})} send fields as json string
    {file: file, info: Upload.jsonBlob({id: id, name: name, ...})} send fields as json blob, 'application/json' content_type
    {picFile: Upload.rename(file, 'profile.jpg'), title: title} send file with picFile key and profile.jpg file name*/
  *data: {key: file, otherInfo: uploadInfo},
  /*
  This is to accommodate server implementations expecting nested data object keys in .key or [key] format.
  Example: data: {rec: {name: 'N', pic: file}} sent as: rec[name] -> N, rec[pic] -> file
     data: {rec: {name: 'N', pic: file}}, objectKey: '.k' sent as: rec.name -> N, rec.pic -> file */
  objectKey: '[k]' or '.k' // default is '[k]'
  /*
  This is to accommodate server implementations expecting array data object keys in '[i]' or '[]' or
  ''(multiple entries with same key) format.
  Example: data: {rec: [file[0], file[1], ...]} sent as: rec[0] -> file[0], rec[1] -> file[1],...
    data: {rec: {rec: [f[0], f[1], ...], arrayKey: '[]'} sent as: rec[] -> f[0], rec[] -> f[1],...*/
  arrayKey: '[i]' or '[]' or '.i' or '' //default is '[i]'
  method: 'POST' or 'PUT'(html5), default POST,
  headers: {'Authorization': 'xxx'}, // only for html5
  withCredentials: boolean,
  /*
  See resumable upload guide below the code for more details (html5 only) */
  resumeSizeUrl: '/uploaded/size/url?file=' + file.name // uploaded file size so far on the server.
  resumeSizeResponseReader: function(data) {return data.size;} // reads the uploaded file size from resumeSizeUrl GET response
  resumeSize: function() {return promise;} // function that returns a prommise which will be
                                            // resolved to the upload file size on the server.
  resumeChunkSize: 10000 or '10KB' or '10MB' // upload in chunks of specified size
  disableProgress: boolean // default false, experimental as hotfix for potential library conflicts with other plugins
  ... and all other angular $http() options could be used here.
})

// returns a promise
upload.then(function(resp) {
  // file is uploaded successfully
  console.log('file ' + resp.config.data.file.name + 'is uploaded successfully. Response: ' + resp.data);
}, function(resp) {
  // handle error
}, function(evt) {
  // progress notify
  console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total) + '% file :'+ evt.config.data.file.name);
});
upload.catch(errorCallback);
upload.finally(callback, notifyCallback);

/* access or attach event listeners to the underlying XMLHttpRequest */
upload.xhr(function(xhr){
  xhr.upload.addEventListener(...)
});

/* 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.
This is equivalent to angular $http() but allow you to listen to the progress event for HTML5 browsers.*/
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, ...})

// These two defaults could be decreased if you experience out of memory issues
// or could be increased if your app needs to show many images on the page.
// Each image in ngf-src, ngf-background or ngf-thumbnail is stored and referenced as a blob url
// and will only be released if the max value of the followings is reached.
Upload.defaults.blobUrlsMaxMemory = 268435456 // default max total size of files stored in blob urls.
Upload.defaults.blobUrlsMaxQueueSize = 200 // default max number of blob urls stored by this application.

/* Convert a single file or array of files to a single or array of
base64 data url representation of the file(s).
Could be used to send file in base64 format inside json to the databases */
Upload.base64DataUrl(files).then(function(urls){...});

/* Convert the file to blob url object or base64 data url based on boolean disallowObjectUrl value */
Upload.dataUrl(file, boolean).then(function(url){...});

/* Get image file dimensions*/
Upload.imageDimensions(file).then(function(dimensions){console.log(dimensions.width, dimensions.height);});

/* Get audio/video duration*/
Upload.mediaDuration(file).then(function(durationInSeconds){...});

/* Resizes an image. Returns a promise */
// options: width, height, quality, type, ratio, centerCrop, resizeIf, restoreExif
//resizeIf(width, height) returns boolean. See ngf-resize directive for more details of options.
Upload.resize(file, options).then(function(resizedFile){...});

/* returns boolean showing if image resize is supported by this browser*/
Upload.isResizeSupported()
/* returns boolean showing if resumable upload is supported by this browser*/
Upload.isResumeSupported()

/* returns a file which will be uploaded with the newName instead of original file name */
Upload.rename(file, newName)
/* converts the object to a Blob object with application/json content type
for jsob byte streaming support #359 (html5 only)*/
Upload.jsonBlob(obj)
/* converts the value to json to send data as json string. Same as angular.toJson(obj) */
Upload.json(obj)
/* converts a dataUrl to Blob object.*/
var blob = upload.dataUrltoBlob(dataurl, name);
/* returns true if there is an upload in progress. Can be used to prompt user before closing browser tab */
Upload.isUploadInProgress() boolean
/* downloads and converts a given url to Blob object which could be added to files model */
Upload.urlToBlob(url).then(function(blob) {...});
/* returns boolean to check if the object is file and could be used as file in Upload.upload()/http() */
Upload.isFile(obj);
/* fixes the exif orientation of the jpeg image file*/
Upload.applyExifRotation(file).then(...)

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 element
  • ngf-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 specify ngf-model-invalid="invalidFiles" to assing the invalid files to a model and find the error of each individual file with file.$error and description of it with file.$errorParam. You can use angular ngf-model-options to allow invalid files to be set to the ng-model ngf-model-options="{allowInvalid: true}".

Upload multiple files: Only for HTML5 FormData browsers (not IE8-9) you have an array of files or more than one file in your data to send them all in one request . Non-html5 browsers due to flash limitation will upload each file one by one in a separate request. You should iterate over the files and send them one by one for a cross browser solution.

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', pattern: 'image/*', delay: 10} that specify the class name for the accepted or rejected drag overs. The pattern specified or ngf-pattern will be used to validate the file's mime-type since that is the only property of the file that is reported by the browser on drag. So you cannot validate the file name/extension, size or other validations on drag. There is also some limitation on some file types which are not reported by Chrome. delay default is 100, and is used to fix css3 transition issues from dragging over/out/over #277.

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.

Resumable Uploads: The plugin supports resumable uploads for large files. On your server you need to keep track of what files are being uploaded and how much of the file is uploaded.

  • url upload endpoint need to reassemble the file chunks by appending uploading content to the end of the file or correct chunk position if it already exists.
  • resumeSizeUrl server endpoint to return uploaded file size so far on the server to be able to resume the upload from where it is ended. It should return zero if the file has not been uploaded yet.
    A GET request will be made to that url for each upload to determine if part of the file is already uploaded or not. You need a unique way of identifying the file on the server so you can pass the file name or generated id for the file as a request parameter.
    By default it will assume that the response content is an integer or a json object with size integer property. If you return other formats from the endpoint you can specify resumeSizeResponseReader function to return the size value from the response. Alternatively instead of resumeSizeUrl you can use resumeSize function which returns a promise that resolves to the size of the uploaded file so far. Make sure when the file is fully uploaded without any error/abort this endpoint returns zero for the file size if you want to let the user to upload the same file again. Or optionally you could have a restart endpoint to set that back to zero to allow re-uploading the same file.
  • resumeChunkSize optionally you can specify this to upload the file in chunks to the server. This will allow uploading to GAE or other servers that have file size limitation and trying to upload the whole request before passing it for internal processing.
    If this option is set the requests will have the following extra fields: _chunkSize, _currentChunkSize, _chunkNumber (zero starting), and _totalSize to help the server to write the uploaded chunk to the correct position. Uploading in chunks could slow down the overall upload time specially if the chunk size is too small. When you provide resumeChunkSize option one of the resumeSizeUrl or resumeSize is mandatory to know how much of the file is uploaded so far.

Old browsers

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:

  • Because of a Flash limitation/bug if the server doesn't send any response body the status code of the response will be always 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.
  • 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.
  • In case of an error response (http code >= 400) the custom error message returned from the server may not be available. For some error codes flash just provide a generic error message and ignores the response text. #310
  • Older browsers won't allow PUT requests. #261

Server Side

CORS

To support CORS upload your server needs to allow cross domain requests. You can achieve 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>

Amazon AWS S3 Upload

For Amazon authentication version 4 see this comment

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',
    data: {
        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, public-read, ...
        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.

ng-file-upload's People

Contributors

a5hik avatar adamnbowen avatar aderowbotham avatar ahmedalejo avatar aitorrodriguez990 avatar alfredbez avatar andresgottlieb avatar anthu avatar anubhav756 avatar arthurflachs avatar atomstar avatar austinpray avatar bazaglia avatar bdomzalski avatar bobchao87 avatar danialfarid avatar danialfaridsada avatar destos avatar edgarnadal avatar ejain avatar lancecaraccioli avatar lookfirst avatar markleusink avatar mtt87 avatar prayagverma avatar radarhere avatar samuraisam avatar vvo avatar xemle avatar zaggino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ng-file-upload's Issues

bower dependency on angular 1.0.7

Since angular 1.0.7 seems not to be in the bower registry. When I update angular-file-upload, I got the message:

Unable to find a suitable version for angular, please choose one:
    1) angular#~1.0.7 which resolved to 1.0.8 and has angularjs-file-upload#1.1.4 as dependants
    2) angular#1.2.0 which resolved to 1.2.0 and has angular-route#1.2.0 as dependants
    3) angular#>= 1.0.2 which resolved to 1.2.0 and has angular-ui-utils#0.0.4 as dependants
    4) angular#* which resolved to 1.2.0 and has Landscape as dependants

Prefix the choice with ! to persist it to bower.json

[?] Answer: 

Is it possible make the angular dependency version a little bit more generic? Thanks.

Cancel upload while uploading

Is there any event or function by which I can cancel uploading at the time of upload?
I got 'process' function, but how can I stop the upload?

Problems to execute others $http.post , get

Hi!

When I'm using the .shim before angular.js and the application is loaded, a call http.get is run and the problem is the "arguments[0]" is ""

if (FormData.__isShim){    //this is true but

var formData = arguments[0]; //this is "" (empty String)
//and...

for (var i = 0; i < formData.data.length; i++) { //this line fails

}

Enviroment IE9

Uploads in to S3 in IE8 are broken

S3 requires that the file attribute from the form data is the last field. Currently it is the first field in the form data.

S3 also doesn't allow any extra parameters (query or form) to be sent. The FileAPI upload sets a cache buster query param by default. This can be fixed by setting the XMLHttpRequest cache config to true. FileAPI upload also sends a callback form parameter. This will require a pull request to allow toggling in the FileAPI project.

-- @rupurt / @willzofsteel

Upload of the same file

Hi

It seems that you cannot choose the same file to upload (onChange will not trigger):
Try (using Chrome):

  1. go to
    http://angular-file-upload.appspot.com/
  2. open Chrome dev tools
  3. try to upload file - there will be POST request
  4. try to upload file the same file - no POST request
    Same for multi select.

Reset input file

Hi, how I can reset the values of the file? After a successful action done after upload I'd like to clean the form to reuse it. I tried $scope.myform.fileName, but its undefined. Thanks.

Nuget package

Any chance to publish one for ASP.NET users? Happy to donate the publishing code, you'll only have to update the version and push the package when you release.

Can't change Content-Disposition name "file"

At the current version, it's not possible to change the Content-Disposition property "name". See line 87.

Here's an example of the header:

Content-Disposition: form-data; name="file"; filename="filename.jpg"
Content-Type: image/jpeg

It would be good if we could change it :-)

Store file before sending

Hello,

I'm pretty new to AngularJS, so if this question seems foolish I apologize :)
So, before I send the file to server I want to store the file until the whole form is validated, and just after users press "Save" button the file should be sent to server along the data colected, instead of sending it when the file is loaded.

Can you help me?

Thank you,
jab3z

IE8 not works!

hi.
I found not works on IE8, because can't bind change on the file input.

Everything looks to be working, but no file in upload folder

I have the tool installed and it appears to be working based on console.log, however I never see the actual image file in the upload folder. I'm on windows 7. I have the folder shared read/write with everyone. What might I be doing wrong?

Error: The body of your POST request is not well-formed multipart/form-data.

I am using angular file upload and getting the error message:
The body of your POST request is not well-formed multipart/form-data.

The purpose is to upload a file to S3 using this method.
http://aws.amazon.com/articles/1434

Here is the code:

$scope.onFileSelect = function($files) {

            for (var i = 0; i < $files.length; i++) {
                var $file = $files[i];

                AWS.get({partId: $stateParams.id, bucket: ""}, function(response){

                    var formData = {
                        key: "/OEM/PARTS/" + $stateParams.id + "/" + $file.name,
                        AWSAccessKeyId: "AKIAJDWFD4T7GQZNZBNQ",
                        acl: 'private',
                        success_action_redirect: "#",
                        policy: response.policy,
                        signature: response.signature,
                        'Content-Type': $file.type
                    };

                    $http.uploadFile({
                        method: 'POST',
                        url: 'https://tennex.s3.amazonaws.com/',
                        headers: {'Content-Type': 'multipart/form-data',
                            //this clears the default Authorization code.
                            Authorization: ""},
                        data: formData,
                        file: $file
                    }).progress(function(evt) {
                        console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
                    }).then(function(data, status, headers, config) {
                        // file is uploaded successfully
                        console.log(data);
                    });
                }, function(){
                    alert("failed to download policy file");
                });
            }
        };

Here is the request and response http headers:

Request URL:https://tennex.s3.amazonaws.com/
Request Method:POST
Status Code:400 Bad Request
Request Headersview source
Accept:/
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Authorization:
Cache-Control:no-cache
Connection:keep-alive
Content-Length:319662
Content-Type:multipart/form-data
Host:tennex.s3.amazonaws.com
Origin:http://localhost:63342
Pragma:no-cache
Referer:http://localhost:63342/app/views/OEM/index.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Request Payload
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="key"

/OEM/PARTS/30/Tesla 2013 05 17.pdf
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="AWSAccessKeyId"

AKIAJDWFD4T7GQZNZBNQ
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="acl"

private
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="success_action_redirect"

------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="policy"

eydleHBpcmF0aW9uJzogJzIwMTMtMTAtMjJUMjI6NTM6NTZaJywgJ2NvbmRpdGlvbnMnOiBbIHsnYnVja2V0JzogJ3Rlbm5leCd9LCBbJ3N0YXJ0cy13aXRoJywgJyRrZXknLCAnT0VNL1BBUlRTLzMwLycgXSwgeydhY2wnOiAncHJpdmF0ZSd9LCB7J3N1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0JzogJyMnLCB9IFsnc3RhcnRzLXdpdGgnLCAnJENvbnRlbnQtVHlwZScsICcnXV19IA==
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="signature"

a55375e793cf0debb8f1077c760b3aa00cff43dd
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="Content-Type"

application/pdf
------WebKitFormBoundary85lPiaZFfRGERy4T
Content-Disposition: form-data; name="file"; filename="Tesla 2013 05 17.pdf"
Content-Type: application/pdf

------WebKitFormBoundary85lPiaZFfRGERy4T--
Response Headersview source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, PUT, POST
Access-Control-Allow-Origin:http://localhost:63342
Access-Control-Max-Age:3000
Connection:close
Content-Type:application/xml
Date:Tue, 22 Oct 2013 22:44:05 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2:wkp3NyL+kJBebuNUN9RYEvsDYLGZEKHXm7rqB7VuxVmPDEAFnXX0SZuo8Dy88hBG
x-amz-request-id:80A54AF54999B9EB

Use $q for the upload service

It would be good if the library returned it's own deferred instead of $http's. This would allow it to also use $q's notify() method to update the progress of the upload instead of having it as a passed option which requires a $apply to do stuff to the scope?

Hope this is clear.

1.0.2

with 1.0.2 i need to call $scope.$apply() manually to apply changes to the scope.

          $http.uploadFile({
            url: $scope.saveImageFiles, 
            file: $file
          }).progress(function(evt) {
            $log.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
          }).then(function(data, status, headers, config) {
            $scope.rounds[$scope.round].image = data.original;
            $scope.$apply();
          }); 

Have to choose/drop files twice before upload starts

I'm unable to figure out why this is happening even though I've been fiddling around with different options. I pretty much copied your demo example but it seems to work differently for me: I need to drop the file/files twice before the upload is initiated. Same with choosing a file using input of type "file". Would you have any clue what I'm possibly doing wrong?

fyi: I'm using 1.2.0rc3 and the 1.0.2 version of file-upload.

Documentation typo

Thank you for this useful library!

I believe the README.md is missing a comma after the data block:

data: {myObj: $scope.myModelObj}
file: $file

Bower compatibility

I use bower for component management. If you're not opposed to it, I could submit a pull request adding bower support.

Non-minified version?

Thank you for this useful library!

Would it be possible to get a non-minified (or, at least, non-all-on-one-line-ified) version of angular-file-upload.js? Then perhaps a separate angular-file-upload.min.js? I would like to understand better what is going on behind the magic.

Incompatibility with ng resource ?

Hi,

when using both ngresource and angularFileUpload, it seems that $http is not overwritten correctly (eg $http does not have a fileupload method).

Here is what I get when console.log($http) just before calling fileUpload():

 function $http(config) {
    config.method = uppercase(config.method);

  var reqTransformFn = config.transformRequest || $config.transformRequest,
      respTransformFn = config.transformResponse || $config.transformResponse,
      defHeaders = $config.headers,
      reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
          defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
      reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
      promise;

  // strip content-type if data is undefined
  if (isUndefined(config.data)) {
    delete reqHeaders['Content-Type'];
  }

  // send request
  promise = sendReq(config, reqData, reqHeaders);


  // transform future response
  promise = promise.then(transformResponse, transformResponse);

  // apply interceptors
  forEach(responseInterceptors, function(interceptor) {
    promise = interceptor(promise);
  });

  promise.success = function(fn) {
    promise.then(function(response) {
      fn(response.data, response.status, response.headers, config);
    });
    return promise;
  };

  promise.error = function(fn) {
    promise.then(null, function(response) {
      fn(response.data, response.status, response.headers, config);
    });
    return promise;
  };

  return promise;

  function transformResponse(response) {
    // make a copy since the response must be cacheable
    var resp = extend({}, response, {
      data: transformData(response.data, response.headers, respTransformFn)
    });
    return (isSuccess(response.status))
      ? resp
      : $q.reject(resp);
  }
} 

I have included angular, and the dependencies in this order:

<script src="js/angular.js"></script> <script src="js/angular-file-upload.js"></script> <script src="js/angular-resource.js"></script> <script src="js/ajout_fichier.js"></script>

loading the modules like this:
var m = angular.module('myApp', ['ngResource','angularFileUpload']);

My Controller looks like this:

    m.controller('AjoutFichierCtrl',function ($scope,$http,$routeParams) {

$scope.file="";
$scope.fileName="";

$scope.$watch('file',function(){
    if ($scope.file==="") return;
    console.log('file changed');
    console.log($http);
    $http.uploadFile({
    url: 'clp/documentsjson', //upload.php script, node.js route, or servlet upload url
    // headers: {'optional', 'value'}
    file: $scope.file
  }).then(function(data, status, headers, config) {
    // file is uploaded successfully
    console.log(data);
  }); 
});
})

The error is $http has no method 'uploadFile'

Bower issue

Running: bower install angularjs-file-upload#1.0.2 returns:

bower not-cached    git://github.com/nervgh/angular-file-upload.git#1.0.2
bower resolve       git://github.com/nervgh/angular-file-upload.git#1.0.2
bower ENORESTARGET  No tag found that was able to satisfy 1.0.2

Additional error details:
Available versions: 0.2.7, 0.2.5, 0.2.4, 0.2.1

$apply cycle not working correctly on IE

Hi,

I ran on a problem when using your code on any IE browser:
When code tries to launch scope.$apply function in "ngFileSelect' directive', an error is thrown in browser console:

Error: $apply already in progress

From research i`ve done seems that somehow IE does not handle apply-digest cycle properly, easy workaround is to wrap $apply block in setTimeout to postpone untill next cycle:

        setTimeout(function () {
            scope.$apply(function () {
                fn(scope, {
                    $files: files,
                    $event: evt
                });
            });
        });

Could you please confirm or reject my issue?

@edit:
Not an issue, found that Angular version was too old. I think that minimal version of Angular needed is worth to be mentioned

Progress bar inconsistent

I have downloaded and played with it.
Progress bar is inconsistent and some times 100% not displayed even, file is uploaded.
I have a doubt, how evt.total is calculated?
is it file size?
if i try to upload same file multiple times, the value is changing slightly
I guess the problem is with evt.total

uploading smaller files like 30/40 KB, not displaying progress bar at all

as you can see below image, 100% is not shown even all files were uploaded
I am using FF 25.0.1
IE8 doesn't have this problem

progress_bar_problem

Error: Unknown provider: $uploadProvider <- $upload at Error (<anonymous>)

I'm trying to inject this module into a controller but when the controller is initialised I get the following error:

Error: Unknown provider: $uploadProvider <- $upload at Error (<anonymous>)

I've included the module (after angular.js).

<script src="/app/components/angularjs-file-upload/angular-file-upload.js"></script>

And injected it into my app:

angular.module('App',  ['ngResource', 'ngSanitize', 'ui.state', 'ui.compat', 'ngCookies', 'ui.bootstrap', 'angularFileUpload'])

And then in my controller:

angular.module('App').controller('FeaturedImageCtrl', ['$scope', '$rootScope', '$state', '$stateParams', 'dialog', '$upload', 'img_src', 'entity_id', 'entity', 'media', function ($scope, $rootScope, $state, $stateParams, dialog, $upload, img_src, entity_id, entity, media) {

However it seems to be the controller which throws the error.

Have I forgotten to do something?

FileAPI.flash.swf doen not shows chosen file

Hi,
After selecting a file, user is not able to see the "file name".

Showing a "file name" in the flash would indicate that user has already chosen a file.

Our application waits with uploading the attachment to the server until user is finished with filling the entire form. Therefore it is important that user can see that they have already cosen file or not.

Regards
Mridul

how do I stall upload until the user pushes a submit

currrently this lib uploaded the file the moment it's chosen.
I need this to behave more like a traditional image upload form: I can choose picture (or pictures) , add some data to the form and then post the whole thing together to the server.
I'm not sure how to implement this with this directive/service.

Great lib btw and thanks for opensourcing it!

__uploadProgress_ not defined in IE9

I had to switch the functions in angular-fileupload-shim "if (!window.FormData)" where the FileAPI is loaded and "if (window.XMLHttpRequest)". Otherwise I got _uploadProgress not defined in IE9.

I'm using Ajax in the beginning when loading the page, so the lookup there for _uploadProgress failed.

if (window.XMLHttpRequest) must be the last call, then it works on my side.

Not working in IE8 and IE9 with jQuery

Adding jquery to the demo prevents it from working in IE8 and 9 (tested using IE10 and switching mode to IE8/9).

If you add the line
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> below the line
<script src="js/angular-file-upload-shim.js"></script> it appears that the ng-file-select directive no longer works - the function specified in the expression is never called.

I think this could be because the change event is not working in IE for file inputs using jQuery but jqLite does support this?

IE8 error: ng-file-select is not called

Under IE8 I keep getting an error:
SCRIPT5007: Unable to get property '__isShim' of undefined or null reference
angular-file-upload-shim.js, line 61 character 6

Then function in ng-file-select isn't called when the file is selected.

I have shim files added in script tags at head tag.

<script src="lib/angular-upload-file/angular-file-upload-shim.js"></script> <script src="lib/angular-upload-file/FileAPI.min.js"></script>

Display image dropped before user submits form

I'm using a submission form which fires $upload.upload(), however, i would like to display the image that is dropped when the user adds an image. I've tried a few things, but doesn't seem to be possible. Any suggestions?

progress doesn't work without shim

I only need to support very modern browsers, so I didn't include the shim at first.
It seems that without the shim loaded, the progress/load event handlers never get set up, and so config.progress is never called and there is no way to update progress in my UI.

System's service name for $upload

Is $upload a standard service in Angular? If not (and it is added by this plugin) - perhaps it should not be using the Angular convention for internal services, and be called "Upload" instead?

Add ability to change 'config.fileFormDataName'

I'm currently working with an api that requires me to send files via a file form data name called "uploaded_file". Is it possible to add the ability to pass custom field names through the config without modifying the source?

Thanks for a great module!

$scope.upload undefined in template view?

Hi, I am not sure why, but the abort button is a bit problematic on my end.
https://github.com/danialfarid/angular-file-upload/blob/master/demo/war/index.html

<button class="button" ng-click="upload[$index].abort(); upload[$index]=null" ng-show="upload[$index] && progress[$index] < 100">Abort</button>

It all boils down to upload[$index] is undefined and that's why .abort() is not working. This is what my controller looks like:

.controller('UploadCtrl', function ($scope, $http, $timeout, $upload) {
    $scope.uploadedFiles = [];

    $scope.onFileSelect = function ($files) {
        $scope.selectedFiles = [];
        $scope.progress = [];

        if ($scope.upload && $scope.upload.length > 0) {
            for (var i = 0; i < $scope.upload.length; i++) {
                if ($scope.upload[i] != null) {
                    $scope.upload[i].abort();
                }
            }
        }

        $scope.upload = [];
        $scope.selectedFiles = $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.progress[i] = 0;
            (function (index) {
                $scope.upload[index] = $upload.upload({
                    url: "./api/uploadfiles", // webapi url
                    method: "POST",// method: POST or PUT,
                    // headers: {'headerKey': 'headerValue'}, withCredential: true,
                    data: { myObj: $scope.myModelObj },
                    file: $file
                    /* set file formData name for 'Content-Desposition' header. Default: 'file' */
                    //fileFormDataName: 'myFile'
                    /* customize how data is added to formData. See #40#issuecomment-28612000 for example */
                    // formDataAppender: function(formData, key, val){} 
                }).progress(function (evt) {
                    $scope.progress[index] = parseInt(100.0 * evt.loaded / evt.total);
                }).success(function (data, status, headers, config) {
                    $scope.uploadedFiles.push(angular.copy($files[index]));
                });
                //.error(...)
                //.then(success, error, progress); 
            })(i);
        }
    };
})

I believe i referenced the files properly:

<script src="ng-components/jquery/jquery.js"></script>
<script src="ng-components/ng-file-upload/angular-file-upload-shim.min.js"></script>
<script src="ng-components/angular/angular.js"></script>
<script src="ng-components/ng-file-upload/angular-file-upload.min.js"></script>

Files do indeed get uploaded, but the $scope.upload contains an array of empty objects all the time like this [{}, {}, {}, ... ] after files for upload are selected.

Do you have any ideas on why this is not working? Thank you.

What does it expect the server to return?

Reading from the java server code, I guess this is the JSON the client expects. I think it's better to document it a little bit. Thanks.

{
    "result": [
        {
            "fieldName": "",
            "name": "",
            "size": "",
            "value": ""
        },
        {
            "fieldName": "",
            "name": "",
            "size": "",
            "value": ""
        },
        {
            "fieldName": "",
            "name": "",
            "size": "",
            "value": ""
        }
    ]
}

Upload isn't including the xsrf cookie

Angular's $http will normally handle sending the xsrf request token for us, and also accepts two config options for specifying the xsrf cookie and header names. It doesn't look like your $http.uploadFile method handles this for us, so for now we have to pull the xsrf value from the cookie and set it in the headers config.

Would it be possible to support xsrf setting like vanilla $http does? Here's a snippet from $http that I think is handling this scenario:

 var xsrfValue = $$urlUtils.isSameOrigin(config.url)
          ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
          : undefined;
      if (xsrfValue) {
        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
      }

Thanks, your directive does work like a charm otherwise tho ๐Ÿ‘

bower does not

Bower does not work since it's depending on angularjs 1.0.7. Also can you please take away the huge jars from the bower update? Thanks.

Doesn't seem to return a promise with angularjs 1.2.0-rc.3

I upgraded angular from rc2 to rc3, and angularjs-file-upload from 0.1.4 to 1.0.2, and it doesn't seem to want to return a promise. Uploading still works perfectly, but I can't do anything afterwards:

this.upload = function(url, file, data) {
    var proxy = this;

    return $http.uploadFile({
        url: url,
        file: file,
        data: data
    }).then(function(res) {
        alert('uploaded') // not firing
    });
}

.then doesn't get executed in IE

This works fine in Chrome and Firefox.
In IE8 the file gets uploaded, but my then-function never gets called (neither does the error-function).

        $scope.onFileSelect = function($files) {
            if ($files.length === 0)
                $scope.data.fileName = null;
            for (var i = 0; i < $files.length; i++) {
                var $file = $files[i];
                $scope.data.fileName = null;
                $scope.uiStates.uploadInProgress = true;
                $http.uploadFile({
                    url: RES.fileUpload,
                    file: $file
                }).then(function(response, status, headers, config) {
                    $scope.uiStates.uploadInProgress = false;
                    $scope.data.fileName = $file.name;
                }, function(response, status, headers, config) {
                    $scope.uiStates.uploadInProgress = false;
                    if (response.data.type === 'error')
                        alert(response.data.message);
                });
            }
        };

Permit method configuration on upload

We should permit the user set the method for http.
Default is POST.

However, you can't execute $http.post, because you will force POST method.
You must use $http(config)!

So, in your service $upload, you should execute:

config.data = formData;
var response = $http(config);

If you wish, give me permission to PR.
๐Ÿ‘

Uploading a file to a REST API with CORS

How can I ass the {withCredentials: true} config parameter to the file upload function?.
Will it be possible also in old IE browsers that load the file API?.

Also I have separated the file upload into a service function, and I am unable to path other form fields along with the file, so I was forced to separate the form submit and the file upload into 2 requests

Sending file upload with form data.

Hi,

Is it possible to send other form data like input strings along with the file upload? Can I just gather the information into the scope and manually send it with the $http.uploadFile function? Thank you for your help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.