The File API has changed
Recently I have been touting how awesome and revolutionary the File API is through a few demo’s. After some feedback on webapps mailing list there have been some major changes to the API and how it works.
I have updated my previous drag and drop upload demo to reflect the API changes, as of Firefox 3.6b3 the API supports both the original API and the updated one. The older model will eventually be dropped, it’s only in there for legacy purposes. To use the demo you will need Firefox 3.6 installed. You can also watch the screencast of it in action.
The biggest change is with the file handling, it is now processed asynchronously with progress events so we can attach listeners. The advantage of this is if a user drags in many files or a large file the UI won’t be locked up while it’s processing the data, much like XmlHttpRequest works.
The File object
The File object has been updated to reflect the new specs changes and has deprecated all the previous methods we used to get the file in various formats e.g. getAsDataUrl(), getAsText(), getAsBinary(). We now handle these methods in the new FileReader object.
It has also renamed the 2 properties for accessing the files name and size from fileName/fileSize to name/size respectively.
The FileReader object
This new object allows us to asynchronously read the contents of a file from a drop event.
var reader = new FileReader(); reader.addEventListener("loadend", TCNDDU.buildImageListItem, false); reader.readAsDataURL(file);
Instead of locking the UI while we wait for it to loop through all the dropped files and then convert them to a DataUrl. The FileReader does this asynchronously. We attach to the onloadend event handler which will fire once the current file has been read into the result attribute. Upon the event firing we then take the event result and add the DataURL to the source of the image to be displayed to the user while it uploads.
Send the binary data
Once we have the file we send it to be processed for an XHR call so we can upload it to the server. Same as above we need to create a file reader and attach to the onloadend event which we then pass to the sendAsBinary() method.
var getBinaryDataReader = new FileReader(); getBinaryDataReader.addEventListener("loadend", function(evt){xhr.sendAsBinary(evt.target.result);}, false); getBinaryDataReader.readAsBinaryString(file);
Similar code we used for the image display handling, but we use the readAsBinaryString() method to return the files binary data for uploading.
Further reading
As the 3.6 final release date is coming closer Mozilla has been ramping up demos and documentation about the File API. Some good documentation on handling files in web applications.
Update: Mika Tuupola has a good article on handling the server side (PHP) part of file uploading.
The hacks blog has recently put up some great information about the File API along with an excellent demo extracting EXIF data from an image.
Now we just need webkit to push out the File API to their nightly builds.
Post filed under: html5, javascript.
Comments
Trackbacks
-
[...] This post was Twitted by kilianbarrera [...]
-
[...] DropMocks : Image Hosting gratuito drag & drop DropMocks è un servizio di image hosting minimalista. DropMocks supporta il drag & drop e i soli Firefox e Google Chrome. DropMocks è un servizio minimalista di image hosting costruito in HTML 5. Il servizio non offre form per l’uplod, neppure il Flash Upload. L’utente che vuole caricare le foto online deve disporre di un Browser che supporta l’HTML 5 (Firefox e Chrome) e la funzione “file upload drag&drop”. (per maggiori info sulla funzione file upload si invita alla lettura del post di CSS Ninja intitolato “The File API has changed“). [...]
-
[...] Being the web geek I am I had to figure out how it functioned. Firefox was easy and I have covered drag and drop uploading already. They also mentioned in their post that Chrome was supported but I know Chrome is yet to [...]
Any word on how this will play with Safari? I’m working on a site that only need to support FF and Safari and this could be a great addition.
Luke, January 23rd, 2010Not sure when they will implement the File API, but there has been a bug filed on webkits bug tracking site requesting they add it.
The Css Ninja, January 23rd, 2010Nice work!
surreydude, February 5th, 2010Tested the demo to work in the release version of Firefox 3.6. Very cool. I noticed after the image is “uploaded” it outputs the image as a base64 encoded data URI… any reason you’re doing this instead of storing the image on the server?
I assume it is possible to simply store the image on the server if desired.
Michael Butler, February 6th, 2010@Michael – It’s actually encoded into a base64 string before it uploads (using the File API). That way I can display the image to the user before any uploading happens. If you disable your network connection and drag in the images it will still display them but will obviously fail on trying to upload them to the server.
The Css Ninja, February 6th, 2010That makes sense! I can see how easy it is then to use the offline data API to store the images locally and upload them later on. Can’t wait to try this out.
Michael, February 6th, 2010When I try the demo in FF3.6 on Ubuntu, Firefox tries to open the dropepd document, instead of uploading them. It seems to ignore the File and Drag And Drop APIs.
Émile Jetzer, February 28th, 2010@Émile – That’s not good, I don’t have a linux machine available for me to test on so I can’t see what’s happening. Can you try my font dragr web app (it uses the file API too) in FF3.6 on your linux machine and let me know if you have the same issue?
The Css Ninja, March 1st, 2010The font dragr doesn’t work either. It seems to be exactly the same issue.
Émile Jetzer, March 1st, 2010@Émile – So I asked around for a few people with linux to try my demo and it’s working for them, but someone did mention that having the Jetpack add-on installed kills the drag and drop functionality but only on linux machines, mac/windows are OK. It’s been filed in the issue tracker so they’re aware of it.
The Css Ninja, March 2nd, 2010I disabled Jetpack, and now it works all right! Thank you!
Émile Jetzer, March 6th, 2010This is really cool! Ubuntu/Firefox isn’t working for me (no Jetpack here), but it works great on my windows machine. I’m going to hack on it for a while to see if I can figure out where Linux is going wrong…
Shawn, April 7th, 2010Shawn, don’t have a linux box to test on so I can’t help you on that front. Only linux issue is the Jetpack plugin but you’ve stated you don’t have it. If you figure out the problem I would be interested to know what it was.
The Css Ninja, April 7th, 2010Could you update your article to include a little blurb on how update.php handles it? As in: $_POST['what goes here???']. I don’t see a name property set anywhere for the post data in your code…
Curt, April 24th, 2010Curt, have a look at this article as it goes into handling the server side of the upload, should help you out.
The Css Ninja, April 24th, 2010@Curt
Alexander Romanenko, May 15th, 2010Using some inspiration from this article, I came up with a JSON solution to upload both binary and/or user data.
http://alex-tech-adventures.com/development/x-html–css–javascript/97-drag-and-drop-upload-using-html5-with-firefox.html
hi,
i’m trying to get the server site working :
my upload.php server side is a simple var_dump($_FILES)
i added an event listener for the ready state change for the xhr to log the response
i get an empty array
firefox 3.6
Guillaume, May 19th, 2010php 5.2.10
apache 2.2.11
on windows XP 32b
Looks nice, but how to store the files on the server?
I’m sorry if I read over this – English is not my first language..
The article you postet on April 24th doesn’t want to help me ;)
Holger, May 23rd, 2010any chance you could let me know how to add “cancel (single object)” and/or “cancel all” method(s)?
chris malcolm, June 6th, 2010Thanks for the sample, really helped me a lot!
However, I discovered a small bug in the handleDrop() function which prevents the file name from being propagated past the drop event. Not really a big deal, but for what I’m doing some information is encoded in the file name which I need to access between the drop and the upload. Anyways, to fix the issue line 96 should be setting reader.name to droppedFileName.
Clark, June 18th, 2010know how I can get the data in a JSP instead of php,because I need to upload the files using JAVA
salvador, June 19th, 2010I just finished a jQuery plugin for this:
http://github.com/weixiyen/jquery-filedrop
Assuming Webkit follows suit, this should be future-compatible, but it works perfectly with FF3.6 right now.
Weixi Yen, June 22nd, 2010WoooWW
Farzan mc, June 23rd, 2010Best thing ever in html
I saw this in gmail and later on in google wave presentation, i didn’t think that i can find the source code …..
Thanks a lot, it will sure come in handy in my projects.
Wooooooooooow :D :D
@Chris M – Not sure what you mean. You want to be able to cancel an image upload?
The Css Ninja, July 5th, 2010@Salvador – Not familiar with JSP but I’m sure they share similar functions. Might be better off asking on a JSP forum.
The Css Ninja, July 5th, 2010@Holger – Have a look at the previous comment I made it has a link to a website which goes into handling the data on the server side.
The Css Ninja, July 5th, 2010I was implementing some of these features by looking in your zip file download… ran in to an issue where you do:
fileUpload.log = container;
But the log property doesn’t carry over 90% of the time in the load event of the XHR… you must have realized this because this part is commented out in your live demo, which uses anonymous functions to keep a handle on the progress bar!
Michael Butler, August 15th, 2010@Michael B – Ah must of forgot to update the demo files zip file, thanks for pointing that out. Source files zip is updated now.
The Css Ninja, August 15th, 2010One of the problems I keep coming up against with drag & drop is the lack of affordance. Even in gmail– I don’t know that I can drag and drop an image until I’ve already tried it, and the actual area I can drop my files in isn’t the “Rich Text” portion of the app, which is debatably where I’d want to see my file.
One of the things I’ve tried is to simply swap classes on input, so that if the user drags a file into the window, the entire window can receive the file. Otherwise, style it to look like a button in my rich text editor so that it behaves normally.
After successful drop, a small “Uploading” message is set with a fixed position, similar to gmail’s “sending…” message.
Upon successful upload, the final file location(s) (I’m resizing along the way) are sent back as jsonp so that img tags can be generated and inserted into the rich text editor.
Not feasible for say, a CMS with multiple Rich Text fields, but less does indeed seem to be more when it comes to managing user expectation of how dropping files should operate.
Adam, September 2nd, 2010I should note it really doesn’t solve the affordance problem, it just seems to be what laypeople expect from my limited experience testing :]
Adam, September 2nd, 2010@Adam – There’s nothing stopping you attaching a drop event on the body which will capture the drop no matter where the user drops it.
The Css Ninja, September 2nd, 2010hey CSS Ninja, thought you might want to know that it seems Chrome version 6 now has the FileReader() class, but it might be incomplete because it says “Object #<a> has no method ‘addEventListener’”. any ideas why you can’t use addEventListener methods on FileReader objects?
Michael Butler, September 15th, 2010@Michael B – Yep I filed a report on their bug tracker a while back, it’s still in their latest canary build also which is v7. However there is an easy work around, use DOM0 event listeners e.g.
The Css Ninja, September 15th, 2010reader.onloadend = f(){}I did make the changes to my font drag web app so that will work in Chrome 6.Ninja, thanks for this tutorial. I’m using Firefox 3.6.10 and when I look at the response in firebug from the post/upload, I just see:
Array
(
)
I see that the file looks like it was posted correctly – is that response to be expected, or should there be content in that array? I’m seeing this both on your demo and on my test on my local machine. Thanks!
Joe, September 22nd, 2010@Joe – If you take a look at this comment I link to another blog that delves into handling the data on the server side, I believe it needs to be handle differently than your normal file upload.
The Css Ninja, September 22nd, 2010Perfect – that did the trick. Obviously, I missed that comment the first time though, so thanks for pointing it out!!
Joe, September 23rd, 2010The code to POST to the upload.PHP does not appear to be correct as $_FILES is null with posted data.
samuel elrod, September 24th, 2010@Samuel it’s very simple and has already been discussed. using the CSS Ninja style ajax upload, there will be no $_FILES array! On PHP, simply do $file_data = file_get_contents(‘php://input’); and you have the file data right there.
Michael Butler, September 24th, 2010Wait where can you define where it is uploading the files? I have tried to use your script and it appears it’s working but doesn’t appear to upload the images anywhere on the server?
sticky, October 17th, 2010@sticky – See here for handling the server side of uploaded images.
The Css Ninja, October 18th, 2010Maybe you will be interested with new JS library, which can be used to add drag&drop upload files functionality which works on Firefox, Safari and Chrome: http://code.google.com/p/html5uploader/ It’s on one of open source licenses.
Woj, November 9th, 2010Hey ninja Great Work here. Thank You.
This is exactly what I need for an intranet app I am working on. However, I wanted to add the functionality of being able to keep adding pictures to the container. Right now if you drag for example 5 pictures, it previews all 5 pictures. And if you drag another 2 it previews only the last 2 I dragged. I wanted it so it keeps on adding them to the list, and also so that they could erase from it. I think that’s the only thing missing.
Plus I am not uploading the pictures to the server, since all I want is the actual path of the pictures. (that’s taken care of)
The example here let’s you keep adding pictures without removing the old ones: http://code.google.com/p/html5uploader/
I looked thru both codes but I can’t figure out what to change in yours to make it work.
Can you please guide me on how to do this.
Thanks in advance.
Robert, November 10th, 2010@Robert – That is an easy change. In the
The Css Ninja, November 10th, 2010TCNDDU.setup()method I attach thedragenterevent and in there I clear the drop area usingdropListing.innerHTML = '';, just remove that line and images won’t be removed.Hey Ninja! Thanks for this great work, very neat!
I have a question as to if it would be possible to pre-populate the dropContainer from file paths?
I have an edit page where users should be able to see the pictures already loaded in the dropContainer.
Is that possible or is that a security threat? I do have the correct file paths tho.
Roberto, November 13th, 2010@Roberto – In short, no. That would be a huge security hole to look through a users filesystem without them knowing or giving permission to do so.
The Css Ninja, November 16th, 2010Thanks for the quick response. I found a workaround the security issue by creating a virtual directory in my intranet mapping to the shared folder where all the images are located. So now I am able to get full URL paths to the images.
Roberto, November 16th, 2010But I still can’t figure out a way to pre-populate the images in the container.
How should I go about doing this?
@Roberto – You can’t iterate over a file system even if you have the full URL path to the images. You would need some server-side code to let you know what files are in the images folder. Do an XHR get request to a webservice that scans the folder returns all the files in JSON. Iterate over the image names, create an img element and append path plus filename, lastly append the documentFragment to the document itself.
The Css Ninja, November 16th, 2010This is amazing. Have you had a chance to try and get this working in Chrome or Safari since they support HTML5?
Jmactacular, November 19th, 2010@Jmactacular – Chrome since version 6 has had support for the File API, only issue is that the
The Css Ninja, November 21st, 2010FileReaderobject doesn’t support DOM2 event listeners so you’ll need to use DOM0 to get it working on chrome.Hi ninja! Great work.
How would I go about uploading the files to a ftp server. I don’t know how to get the $_FILES[] global array since one doesn’t exist since you don’t use one, or do you?
Well I need to upload the files to a ftp server using php, I need to be able to get the all the files from the $_FILES[] array once my form is submitted but I can’t see how to it with your implementation of drag and drop. Is it possible?
Thank you
Bob, December 8th, 2010@Bob – I’ve mentioned a few times in the comments of this article that goes into the serverside handling of the file upload. I’ve also updated the article to link to it.
The Css Ninja, December 8th, 2010please give me a Demo code ,this code isn’t upload.php file
luokai, January 4th, 2011Brilliant! thanks for the demo.
droid, January 14th, 2011File opens in IE and Chrome but works a treat in FF
Thanks for all the links posts too will give it all a good read… then drop files directly to database through PHP.
Perfect for my project with special needs kids THANKS
Hi Ninja,
its really very cool functionalityand very good. I have implemented
in one of my project.
Still I got one problem.
is there any limitation on the size of bytes on total files uploaded. If i upload total 7 files . each files are of more then 1 Mb size and seems like it does not upload the 7th file.
and getBinaryDataReader.readAsBinaryString(file); gives error on upload. its exception error. so flow does not interrupted but the file was not uploaded.
please suggest on this if you got any idea.
Thanks
Dipak Basantani, January 21st, 2011Hello There,
Thanks for such a nice plug-in, this is what I am looking for, This plugin is working fine on firefox,but it does not working on other browsers, Could u please focus on the same, so that user can enjoy the plugin for other browser.
–
Sarvesh, February 23rd, 2011Thanks & regrads
Sarvesh
Ryan: It works fine. However, the upload.php script does NOT see any $_POST variables. The script gets called, but the $_POST array is empty. Using production 3.6 browser.
Thoughts?
Larry
Larry Bradley, February 27th, 2011@Larry B –
Should you not be accessing the $_FILES super global to access uploaded files?
The Css Ninja, February 28th, 2011how I can get the data in a JSP instead of php,any comments
manikavasakam, April 15th, 2011@manikavasakam –
Don’t know JSP so can’t help you there.
The Css Ninja, April 21st, 2011Thank you very much for your the effort into this code, but please let me say that it is quite useless without a working upload.php file. I read the links you provided about and tried long to work it out, but without success. Many of us are not so proficiency in PHP to change the code to fit it into your example. So, meanwhile some guru publishes here a working upload.php, none of us will fully enjoy your code in our applications.
Enrico, June 20th, 2011@Enrico –
If you read the comments you’ll see I mention *many* times where to find server side help.
Ryan Seddon, June 24th, 2011tested the live demo on chrome 12.0.742.112/Win, there’s an error popped out on the devtool’s console, it says:
Object # has no method ‘addEventListener’
on: /demo/drag-drop_upload/v2/:114
I think the latest File API don’t have addEventListener or something, but i’ve successfully implemented the same functionality using:
FileReader.onloadend = function(){};
and it works on chrome 12, FF4/5, and opera 11
the only problem that I have is with readAsBinaryString on file larger than 100KB, the onloadend seems to never called, even after waiting for 10 minutes (yupz, i actually waited for that long …. @__@)
as you might already know, i use readAsBinaryString for uploading to the server … but i never got a chance to upload anything, as everytime i try to readAsBinaryString it never ends … >.<
would really appreciate some help, tried googling this, but doesn't seem to be anything to help me …
in the meantime will try to slice the file for readAsBinaryString, it that's possible at all …
cheers
pilus, July 22nd, 2011I went through all the above post but your are redirecting to http://www.appelsiini.net/2009/10/html5-drag-and-drop-multiple-file-upload when ever some one asks for the server side script.
I tried many ways with $_POST, $_FILES and then finally file_get_contents(“php://input”). $_POST and file_get_contents(“php://input”) are returning some data which is not giveing proper result when sent to image tag in PHP as below
$file_data = file_get_contents(“php://input”);
print “”;
This is not useful for me until I store the posted data into server.
If anyone have got success with PHP. Please paste the code in this thread.
Thanks
Praveen, July 29th, 2011@pilus –
Yes I too came across DOM2 event handling not working on FileReader, I filed a bug a long time ago but it still hasn’t been fixed.
Haven’t come across your issue with readAsBinaryString not working. Do you have a testcase for this?
Ryan Seddon, August 3rd, 2011Hi Ryan,
Thanks so much for providing this demo. The code reads really well and is a great starting point I feel for many developers (including me) getting their head around the Drag and Drop capabilities.
Keep up the great work.
Anton Babushkin, August 4th, 2011Similar to your code i’ve came up with this
http://www.ashantyk-design.com/dev-3-Upload%27em+JS
I said similar because i pulled out the % loading thing because that shows the progress of the file being loaded into the browser, not the server and i put in a connection limit part with queueing.
Also i extended the delete/cancel function. users can delete uploaded files after upload completion, using a session variable so they won’t delete any files that they didn’t uploaded (security reasons)
Barbieru Gabriel, August 6th, 2011Hi Ninja!
Great work! I was inspired by your drag and drop uploader so I rewrote it and optimized it to work also in chrome browser.
The demo is on:
http://www.ninja-scripts.com/demos/drag/
and the uploaded files:
http://www.ninja-scripts.com/demos/drag/files
Regards,
Nenad, November 23rd, 2011Nenad
Can the demo work?
Uncaught TypeError: Object # has no method ‘addEventListener’
zero, December 1st, 2011@zero –
There’s been a long standing bug in Chrome not supporting DOM2 event binding on
FileReader().However you can use DOM0 event binding to get around in the mean time.
Ryan Seddon, December 21st, 2011