65

Does there exist a good file uploader with good integration (a directive) for AngularJS?

I am looking for something that is easy to style and supports HTML5 drag and drop etc.

Someone will probably say that its easy to use an existing uploader and integrate it into AngularJS - to that I'll say: if its easy then someone should have done it already.

5
  • jsfiddle.net/danielzen/utp7j Don't you know that Giuthub page that showcase some great example for basic process : github.com/angular/angular.js/wiki/JSFiddle-Examples Commented Oct 19, 2012 at 21:41
  • 2
    @Spir While it might work, that's not the best example of angular at work. It throws dependency injection out of the window, and also does heavy DOM manipulation and event binding inside of the controller. Commented Oct 22, 2012 at 0:00
  • 17
    +29, 27 starred. "closed as off topic". Commented Oct 17, 2013 at 10:29
  • 7
    when i asked this question, there wasn't a file uploader for angular. So it wasn't off topic at that time, and it seems to be still pretty useful to people even now. Commented Oct 19, 2013 at 2:35
  • 3
    mkoryak - I'm quite sure that @Quibblesome is actually making a dig at the 'new' super-strict-and-thus-not-so-useful site policy, and not at your question. Commented Jan 6, 2015 at 12:47

5 Answers 5

47

I actually have rolled my own uploader once... but only because I didn't like any of the already made JQuery ones. Unfortunately that's proprietary and I can't post it on the internet... but... I can show you how to use just about any JQuery plugin from Angular:

Someone will probably say that its easy to use an existing uploader and integrate it into AngularJS - to that i'll say: if its easy then someone should have done it already.

Let's presume I have a jQuery plugin that works by selecting a div and calling pluginUploadCall() on it...

app.directive('myJqueryPluginUploader', function() {
   return {
      restrict: 'A',
      link: function(scope, elem, attr, ctrl) {
          // elem is a jQuery lite object
          // or a jQuery object if jQuery is present.
          // so call whatever plugins you have.
          elem.pluginUploadCall();
      }
   };
});

And here's how it would be used.

<div my-jquery-plugin-uploader></div>

Angular actually integrates really well with jQuery so any plugins that work in jQuery should work pretty easily in Angular. The only trickiness comes in when you want to keep Dependency Injection alive so you can keep your Angular App testable. JQuery isn't very good at DI, so you may have to jump through some hoops.

If you wanted to roll your own, I can tell you I did something like this:

app.directive('customUploader', function(){
    return {
       restrict: 'E',
       scope: {},
       template: '<div class="custom-uploader-container">Drop Files Here<input type="file" class="custom-uploader-input"/><button ng-click="upload()" ng-disabled="notReady">Upload</button></div>',
       controller: function($scope, $customUploaderService) {
          $scope.notReady = true;
          $scope.upload = function() {
             //scope.files is set in the linking function below.
             $customUploaderService.beginUpload($scope.files);
          };
          $customUploaderService.onUploadProgress = function(progress) {
             //do something here.
          };
          $customUploaderService.onComplete = function(result) {
             // do something here.
          };
       },
       link: function(scope, elem, attr, ctrl) {
          fileInput = elem.find('input[type="file"]');
          fileInput.bind('change', function(e) {               
               scope.notReady = e.target.files.length > 0;
               scope.files = [];
               for(var i = 0; i < e.target.files.length; i++) {
                   //set files in the scope
                   var file = e.target.files[i];
                   scope.files.push({ name: file.name, type: file.type, size: file.size });
               }
          });
       }
});

Where $customUploaderService would be a custom service you create with Module.factory() that uses $http to post the files and check the progress on the server.

I know that's vague, and I'm sorry that's all I can provide, but I hope that helps.

EDIT: The drag and drop file upload is a bit of a trick of CSS, BTW... for Chrome and FF, what you do is put the in a containing div... then do something like this:

<div class="uploadContainer">Drop Files Here<input type="file"/></div>
div.uploadContainer {
   position: relative;
   width: 600px;
   height: 100px;
}

div.uploadContainer input[type=file] {
   visibility: hidden;
   position: absolute;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
}

... now anything you drop on that div will really be dropped on the file upload, and you can make the div look like whatever you want.

Sign up to request clarification or add additional context in comments.

9 Comments

thanks for answering pretty much all of my angluarjs questions so far. Ill accept them as soon as i work through them :) This info is really good since im just starting out and there isnt much available
lol... I didn't realize I'd done that. I really like Angular and I think the documentation is lacking so I'm trying to help out.
angular seems really interesting. i wish i didnt haven to forget all i know about writing client side code to use it... but i guess thats how really interesting things usually are.
Well, in my mind the problem is that for more than a decade now people haven't treated JavaScript with much respect as a programming language. Which is why we haven't seen too many frameworks like this until recently. I mean, I remember the times when JS was avoided at all costs because things just didn't work between browsers. Or hell, people just had it turned off.
ok, one more question. how do you post the files? $http uses ajax and you cant ajax files. i can get around it using iframes, or a file uploader lib, but is there actually an angular way to do file uploads without having to resort to those things (that works on ie7+)
|
25

You can give AngularJS.ngUpload a try.

It's an HTML5-free solution that uses an invisible iFrame for file upload. Since it does not rely on HTML5, it works across browser!

Sample code:

<form action='/server/upload/handler' ng-upload="callbackFunction">
   <!-- other form inputs goes here -->
   <input type="file" name="anyEasyName" />
   <input type="submit" class="upload-submit" value="Submit" />
</form>
<div>{{uploadReport}}</div>

Any html element that supports a click event can be used to submit a form marked with the ngUpload directive, only that such elements must be marked with the upload-submit css class (as the case with the input[type=submit] above.

The example below uses a styled div to submit the form.

<form action='/server/upload/handler' ng-upload="callbackFunction">
   <!-- other form inputs goes here -->
   <input type="file" name="anyEasyName" />
   <div style="cursor: pointer; padding: 5px" class="upload-submit">Submit</div>
</form>
<div>{{uploadReport}}</div>

You can make your /server/upload/handler spit a valid url, so that {{uploadReport}} can be used to set the src of an <img> tag, like so:

<img ng-src={{uploadReport}} />

and see the uploaded image appear immediately!

The ngController for the above examples is:

var UploadCtrl = function ($scope) {
     $scope.callbackFunction = function(contentOfInvisibleFrame) {
         $scope.uploadReport = contentOfInvisibleFrame;
     }
}

The ngUpload directive can be registered with your AngularJS application module viz:

var mainApp = angular.module('MainApp', ["ngUpload", ...]);

and added to your document as:

<html ng-app="MainApp">

</html>

AngularJS.ngUpload works in the context of a ngController; and such you can have as many uploaders as possible in a single ngController. For example:

<form action='/server/upload/handler' ng-upload="callbackFunction1">
   <!-- other form inputs goes here -->
   <input type="file" name="anyEasyName" />
   <input type="submit" class="upload-submit" value="Submit" />
</form>
Server response: {{uploadReport1}}

<form action='/server/upload/handler' ng-upload="callbackFunction2">
   <!-- other form inputs goes here -->
   <input type="file" name="anotherEasyName" />
   <input type="submit" class="upload-submit" value="Submit" />
</form>
Server response: {{uploadReport2}}

to be served by:

var UploadCtrl = function ($scope) {
     $scope.callbackFunction1 = function(contentOfInvisibleFrame) {
         $scope.uploadReport1 = contentOfInvisibleFrame;
     }

     $scope.callbackFunction2 = function(contentOfInvisibleFrame) {
         $scope.uploadReport2 = contentOfInvisibleFrame;
     }
}

A NodeJS-based upload handler demo of this directive can be found at http://ng-upload.eu01.aws.af.cm.

An ASP.Net MVC and NodeJS sample codes can be found on the project website at github.com/twilson63/ngUpload/tree/master/examples

Hope this helps.

Comments

12

I have put together a simple/light angular directive with polyfill for browsers not supporting HTML5 FormData here:

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

You can send other model object along with the file to the server. Here is the demo page:

http://angular-file-upload.appspot.com/

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

<div ng-controller="MyCtrl">
  <input type="text" ng-model="myModelObj">
  <input type="file" ngf-select ng-model="files" >
</div>

controller:

Upload.upload({
    url: 'my/upload/url',
    data: {myObj: $scope.myModelObj},
    file: $scope.files
  }).then(function(data, status, headers, config) {
    // file is uploaded successfully
    console.log(data);
  }); 

2 Comments

How to start the upload on submit button?
Call the js part on submit button ng-click. I have updated the code since the new version has support for ng-model directive.
7

If you want to handle multiple files, try this

jQuery File Upload Angularjs wrap from the original author (blueimp)

I think it is the most powerful uploader so far.

Comments

5

I recently wrote a directive that supports native multiple file uploads.

Example usage:

<lvl-file-upload
    auto-upload='false'
    choose-file-button-text='Choose files'
    upload-file-button-text='Upload files'
    upload-url='http://localhost:3000/files'
    max-files='10'
    max-file-size-mb='5'
    get-additional-data='getData(files)'
    on-done='done(files, data)'
    on-progress='progress(percentDone)'
    on-error='error(files, type, msg)'/>

You can find the code on github, and the documentation on my blog

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.