Drag and Drop File Upload with AngularJS

A reusable AngularJS directive leveraging HTML5 Drag and Drop and the FileReader API

Directives allow you to create new HTML elements, attributes, classes, or comments that can transform the behavior of the DOM. A better way of thinking about directives is “a way to teach HTML new tricks.” In this example, you will see how to leverage directives to solve a common drag and drop problem that can be reused in the future.

See it in action

Note Angular directives are complex. This is by no means a comprehensive tutorial. Find more info on this topic here.

Reusability

Almost every web application today in some way shape or form supports drag and drop. In our particular example, our users required the ability to upload files/images via drag and drop. I immediately looked to directives for the solution; knowing that having this reusable component would come in handy in the future.

Diving into the directive

At a high level, the directive does two major things:

First, it binds to the ‘dragover’ and ‘dragenter’ events on the element the directive is being applied. When these events are triggered, the default browser behavior (displaying the image or file) is prevented via event.preventDefault(). Also, the ‘effectAllowed’ property on the ‘dataTransfer’ property of the event is set to ‘copy’. This restricts the type of drag the user can perform on the element.

Next it binds to the ‘drop’ event on the element the directive is being applied. When the drop event is triggered, the FileReader API is put to use. This API allows us to base64 encode the dropped files making it easy for client/server transfer via REST protocol.

The entire source code (written in CoffeeScript) for the directive can be found here.

Using the Directive

Using the directive is as simple as specifying ‘file-dropzone’ as an attribute on the element you wish to receive drop events. At a minimum, you will also need to supply a ‘file’ attribute; The base64 encoded file data will be stored in this attribute.

The directive can be configured to only process certain mime types. This is accomplished by specifying an an array of valid mime types to the ‘file-dropzone’ attribute. Also, a max file size (in MB) can be supplied to limit the size of the file being uploaded. This is done by providing an attribute ‘max-file-size’

This JSFiddle example shows how to only accept drop actions for png, jpeg, and gif images that are less than or equal to 3MB.

In Closing

If you approach directives with a reusable mindset, you’ll find it yields the following:

  • The ability to write code and easily share it amongst different projects and code bases.
  • Saved time and development effort in the future.

Posted Tuesday, August 13th, 2013 · Back to Top

SPONSOR

Add Comment

32 Comments 0 Mentions

  1. Foxandxss Author Editor

    Lovely example. I love it.

    On the other hand, you can use plunker (http://plunker.co) to paste coffeescript too :)

    · Reply

  2. Louis Sivillo Author Editor

    I created a bower module which contains this directive. For ease use in your front end app install by executing the command bower install angular-file-dnd

    · Reply

  3. t00f Author Editor

    Really nice and useful article / directive !
    I needed to tell jQuery dataTransfer property according to its documentation:

    // add the dataTransfer property for use with the native drop event
    // to capture information about files dropped into the browser window
    jQuery.event.props.push( “dataTransfer” );

    Hope it could help someone else ! ;)

    · Reply

    • Kevin Author Editor

      Thanks, this saved me some time!

      · Reply

    • Simon Author Editor

      This should be set in the introduction of this tutorial.

      Thanks a lot for sharing and thanks to Louis for this great post !

      · Reply

    • Louis Sivillo Author Editor

      I have updated angular-file-dnd (https://github.com/onemightyroar/angular-file-dnd) to support angular + jQuery.

      If you are using the plugin as a bower component, update to version 1.0.0

      · Reply

  4. Vasu Author Editor

    Nice tutorial. I have one question. can we do read, write, update the josn file?. Please suggest some tutorials.

    · Reply

  5. KevinJohnson Author Editor

    You have shared really helpful tutorials. I like it. Thanks for sharing such a great stuff.

    · Reply

  6. abbey Author Editor

    It good learning new tools… i will try my hand on this one of theses days… thanks for sharing

    · Reply

  7. Michael Caputo Author Editor

    This might be a really dumb question, but I don’t see where the file is being uploaded to the server at. Can someone point me in the correct direction?

    I’ve also had to modify the script slightly to work with AngularJs 1.2.0

    adding “originalEvent” to everywhere that has: event.dataTransfer

    · Reply

    • Michael Caputo Author Editor

      Apologies, i see now that this is meant for a RESTful system, therefore transmits the image data via base64 (wasn’t initially obvious at first glance).

      Is it possible to convert this script to upload a file directly to a server from the form?

      · Reply

      • Louis Sivillo Author Editor

        Michael, Feel free to fork the directive here: https://github.com/onemightyroar/angular-file-dnd

        I believe there are two ways to do this:
        1) Pass a function to the directives scope via the ‘&’ symbol. This function can then be invoked during drop event processing. Obviously, this function would be responsible for making the XHR request
        2) Pass an endpoint to the directive and have the directive make the XHR to the provided endpoint

        IMO, option 1 is the better approach. This is a file drag and drop directive. Adding more functionality/responsibility to it (sending XHR requests) makes the directive less reusable going forward.

        ·

  8. Louis Sivillo Author Editor

    Michael,

    The actual file upload does not take place within this directive. This directive sets you up nicely for file upload because the transferred data is base64 encoded (and two way data bound to your controller). To submit it, embed this directive into a . Via ‘ng-submit=”boundControllerFunction()”‘ on the form you can use $http or $resource to send the data along to the server. Hope this helps!

    RE: AngularJS 1.2.0-rc.2: this directive is only guaranteed to work with AngularJS 1.0.8 as specified within the bower.json file here: https://github.com/onemightyroar/angular-file-dnd

    · Reply

  9. Sylvain RAGOT Author Editor

    Thanks for sharing this pretty good module ! It looks like so easy to deals with drag and drop !

    Instead of an image, I have to manage CVS files, and I have 2 questions :

    1) To display its content, I guess I have to handle and parse the droped file in a controller. But I don’t understand how I can get the content ?

    2) how can I upload the file to a remote server ?

    · Reply

  10. طراحی سایت Author Editor

    Thanks, it’s very helpful. I will follow in github

    · Reply

  11. Adil Meo Author Editor

    Thanks 4 this useful and helpful article !!! keep working like this :-)

    · Reply

  12. Michael Caputo Author Editor

    Hi there!
    I’m trying out your directive, however I can’t seem to extract the image data from the dropzone. Data is being passed via base64, but I am missing everything else (name, size, type). I don’t understand how to pass it though the form to my controller. It seems it is meant to be done through the file=”" attribute, but like i said, i’m only getting the base64 data.

    What am I missing? Thanks so much!

    · Reply

    • Louis Sivillo Author Editor

      Michael,

      Short Answer:
      To get access to the file name simply bind a controller value to the ‘fileName’ attribute of the directive. If you want file, name, size, and type register to the following message ‘file-dropzone-drop-event’ via:
      $scope.$on ‘file-dropzone-drop-event’, handler
      All the info you want will be there!

      Longer Answer:
      The ultimate goal of this directive is to easily perform a file upload from your computers file system to a server. The HTML5 DnD File API, which is used by my directive, gives you the file in base64 format (this is awesome because that’s how servers want the data). Browsers can display images (if that’s what you are dragging and dropping) because they can handle base64 encoded strings as the ‘src’ attribute of an ” tag.

      If you are trying to access the contents of the file being dragged and dropped (text of a csv file, image data etc…), my directive is not going to get you 100% of the way there.
      You can use the file name or base64 encoded file blob in conjunction with the FileReader API (as documented here http://www.html5rocks.com/en/tutorials/file/dndfiles/ – see Reading Files section). I would suggest doing this in a service or creating an entirely new directive so you don’t have a messy controller.

      Hope this helps.

      · Reply

  13. Roberto Robles Author Editor

    Hi,

    I have added this directive to my project and it works great, but for some reason on Firefox (25.0.1) the drop event don’t seems to be working, does this directive is compatible with all browsers? Or am I missing something on my implementation?

    Btw, great work Louis!

    Apologies for my bad english.

    · Reply

    • Louis Sivillo Author Editor

      Roberto,

      Sorry for the delayed response. My implementation had a bug with respect to firefox. I have updated the code to resolve this issue. To incorporate this fix into your project, please update to the latest version (1.0.3) of angular-file-dnd via ‘bower update angular-file-dnd’

      -Louis

      · Reply

  14. Julio Indriago Author Editor

    Hi Louis,

    I’m giving a try to your directive.
    A little message i receive from bower install. ;)

    mismatch Version declared in the json (1.0.0) is different than the resolved one (1.0.3)

    I’ll let you know how it went.

    Regards!

    · Reply

  15. Hayley Clare Author Editor

    Thanks for this, we’re using drag and drop on our production boards speeding up productivity no end.

    · Reply

  16. Xe tap di Author Editor

    Thanks, it’s very helpful. I will follow
    Hope it could help someone else ! :)

    · Reply

  17. درب اتوماتیک Author Editor

    You apparently made a lot of tunning in your setup, and added an opcode cache, but what about doing the same with apache ?

    · Reply

  18. rey Author Editor

    https://github.com/myPHPDelights/angular-dropzone

    This is an integration of dropzone js and angular

    · Reply

  19. Xe hoi dien tre em Author Editor

    Nice Post. Thank you very much for Sharing.

    · Reply

  20. Tom Author Editor

    Very nice post!

    How would I add visual feedback on drag/hover over my dropzone?

    · Reply

  21. Mersin Web Tasarim Author Editor

    I was looking for web design tool. Thanks for the post. Sincerely.

    · Reply

  22. May in sieu toc Author Editor

    Thanks, it’s very helpful. I will follow in github

    · Reply

  23. خرید ملک در آلانیا Author Editor

    We’re a gaggle of volunteers and starting a brand new scheme in our community. Your website offered us with useful information to paintings on. You’ve performed a formidable job and our entire community might be thankful to you.

    · Reply

  24. Thomas Author Editor

    Hi!

    Nice article, how would you go about to create this for multiple files?

    · Reply

 

Join the Conversation

Back to Top

Build Internet by One Mighty Roar. Since 2008.