Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Here is my html form

<form name="myForm" ng-submit="">
    <input ng-model='file' type="file"/>
    <input type="submit" value='Submit'/>
</form>

I want to upload an image from local machine and want to read the content of the uploaded file. All this I want to do using AngularJS.

When I try to print the value of $scope.file it comes as undefined.

share|improve this question
    
what about: stackoverflow.com/questions/12979712/… –  Cherniv Sep 2 '13 at 10:32
    
angulartutorial.net/2015/03/… –  prash Mar 21 at 18:28

11 Answers 11

up vote 137 down vote accepted

Please note that solutions that use FormData(), such as the ones presented here in other answers, do not work correctly in older versions of Internet Explorer. The correct solution should use a backup strategy for that, such as using iframes. There are already many Angular.js modules to perform file uploading:

I would advise you to choose one and use it, or have a look at its code.

share|improve this answer
1  
One more solution (IaaS for file uploading): github.com/uploadcare/angular-uploadcare –  David Avs Oct 10 '14 at 7:25
4  
EggHead has a good video on this - egghead.io/lessons/angularjs-file-uploads –  Adam Zerner Nov 5 '14 at 17:17
    
@fregas, true, but in this case "older" includes IE 9. –  Samuel Neff May 26 at 1:33

The easiest is to use HTML5 API, namely FileReader (http://jsfiddle.net/f8Hee/1/).

HTML is pretty straightforward:

<input type="file" id="file" name="file"/>
<button ng-click="add()">Add</button>

In your controller define 'add' method:

$scope.add = function(){
  var f = document.getElementById('file').files[0],
      r = new FileReader();
  r.onloadend = function(e){
    var data = e.target.result;
    //send you binary data via $http or $resource or do anything else with it
  }
  r.readAsBinaryString(f);
}

Browser Compatibility

Desktop Browsers

Firefox(Gecko) 3.6(1.9.2), Chrome 7, Internet Explorer* 10, Opera* 12.02, Safari 6.0.2

Mobile Browsers

Firefox(Gecko) 32, Chrome 3, Internet Explorer* 10, Opera* 11.5, Safari 6.1

Note : readAsBinaryString() method is deprecated and readAsArrayBuffer() should be used instead.

share|improve this answer
1  
please explain what is happening here! Whats reader? –  Bhumi Singhal Mar 22 '14 at 18:49
5  
FileReader is a class from standard HTML5 File API w3.org/TR/FileAPI. It allows you to read data from file specified in html input element and process it inside onloadend callback function. You don't need any library to use this API, its already in your browser (unless you use very old one). Hope this helps. –  yagger Mar 23 '14 at 8:18
    
If i need to read an .xls file how can i do it ? –  Bhumi Singhal Mar 23 '14 at 8:19
2  
This is already a different topic. I only can advise you not to use proprietary formats in your app, use de facto standard transition formats CSV or JSON. It has wide support in many JS libraries and custom parser is easy to write and maintain. In case you desperately need to parse almighty .xls, then there are solutions available online, probably very limited. –  yagger Mar 24 '14 at 7:22
5  
FileReader.readAsBinaryString is deprecated as of 12 July 2012 Working Draft from the W3C. –  Shane Stillwell Apr 24 '14 at 13:50

Below is working example of file upload:

http://jsfiddle.net/vishalvasani/4hqVu/

In this one function called

setFiles

From View which will update the file array in controller

or

You can check jQuery File Upload using AngularJS

http://blueimp.github.io/jQuery-File-Upload/angularjs.html

share|improve this answer
    
Hi, i was looking for something through which I can just upload one file and display just below it. However in your example I was not able to do same. Dont mind but I am new to this angularjs and my intention to learn to do this particular objective in a simpler yet robust way. –  Aditya Sethi Sep 4 '13 at 14:44
    
This helped a lot. Thanks! –  RachelD Dec 5 '13 at 21:03
    
Excellent example without using an additional library / extension. Thanks. –  markdsievers Apr 5 '14 at 4:01
3  
Very helpful, just a note.. this uses File API which doesn't work in IE9 or below. –  ArjaaAine Jul 18 '14 at 22:21

You can achieve nice file and folder upload using flow.js.

https://github.com/flowjs/ng-flow

Check out a demo here

http://flowjs.github.io/ng-flow/

It doesn't support IE7, IE8, IE9, so you'll eventually have to use a compatibility layer

https://github.com/flowjs/fusty-flow.js

share|improve this answer

The blog post at this location (thanks to Jenny Louthan) contains a directive and some sample code. And it just works straight out of the box. The accompanying explanation is very useful.

http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

share|improve this answer

I tried all alternatives that @Anoyz (Correct answer) gives... and the best solution is https://github.com/danialfarid/angular-file-upload

Some Features:

  • Progress
  • Multifiles
  • Fields
  • Old browsers (IE8-9)

It's work fine for me. You just have to pay attention to instructions.

In server-side i use NodeJs, Express 4 and Multer middleware to manage multipart request.

share|improve this answer

http://jsfiddle.net/vishalvasani/4hqVu/ works fine in chrome and IE (if you update CSS a little in background-image). This is used for updating progress bar:

 scope.progress = Math.round(evt.loaded * 100 / evt.total)

but in FireFox angular's [percent] data is not updated in DOM successfully,although files are uploading successfully.

share|improve this answer
    
For FF you can listen to load event and if the length is computable then fire a progress event to indicate the successful upload. github.com/danialfarid/angular-file-upload already takes care of that. –  danial Jan 9 '14 at 7:36
    
It's there, but in given fiddle also it's checked and applied. Still no hope in FF. –  mayankcpdixit Jan 9 '14 at 7:41
    
I think if you just call uploadProgress inside uploadComplete it should work for FF –  danial Jan 9 '14 at 17:47
    
NO it doesn't, and even if it does can you please explain why? I've give a link to fiddle in my post. If possible can you please update it to working in FF and comment solution's link here? –  mayankcpdixit Jan 10 '14 at 5:55
    
What version of Firefox? –  danial Jan 10 '14 at 15:43

You may consider IaaS for file upload, such as Uploadcare. There is an Angular package for it: https://github.com/uploadcare/angular-uploadcare

Technically it's implemented as a directive, providing different options for uploading, and manipulations for uploaded images within the 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 }}"
 />

More configuration options to play with: https://uploadcare.com/widget/configure/

share|improve this answer

Easy with a directive

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] });
            }                                       
        });
    }
};

In the directive we ensure a new scope is created and then listen for changes made to the file input element. When changes are detected with emit an event to all ancestor scopes (upward) with the file object as a parameter.

In your controller:

$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);
    });
});

Then in your ajax call:

data: { model: $scope.model, files: $scope.files }

http://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/

share|improve this answer

This should be an update/comment to @jquery-guru's answer but as I don't have enough rep it will go here. It fixes the errors that are now generated by the code.

https://jsfiddle.net/vzhrqotw/

The change is basically:

FileUploadCtrl.$inject = ['$scope']
function FileUploadCtrl(scope) {

To:

app.controller('FileUploadCtrl', function($scope)
{

Feel free to move to a more appropriate location if desired.

share|improve this answer

i think this is the angular file upload:

ng-file-upload

Lightweight Angular JS directive to upload files.

Here is the DEMO page.Features

  • Supports upload progress, cancel/abort upload while in progress, File drag and drop (html5), Directory drag and drop (webkit), CORS, PUT(html5)/POST methods, validation of file type and size, show preview of selected images/audio/videos.
  • Cross browser file upload and FileReader (HTML5 and non-HTML5) with Flash polyfill FileAPI. Allows client side validation/modification before uploading the file
  • Direct upload to db services CouchDB, imgur, etc... with file's content type using Upload.http(). This enables progress event for angular http POST/PUT requests.
  • Seperate shim file, FileAPI files are loaded on demand for non-HTML5 code meaning no extra load/code if you just need HTML5 support.
  • Lightweight using regular $http to upload (with shim for non-HTML5 browsers) so all angular $http features are available

https://github.com/danialfarid/ng-file-upload

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.