Grow your CSS skills. Land your dream job.

Ajax Image Uploading (With Less Suck)

Published by Guest Author

This technology demo is courtesy of ZURB and the post was co-authored by ZURB and Chris.

How do you upload images now?

You select a file and click upload. Simple right? Except once you select your image you can no longer see what was selected. The name of the file is at the end of the input, and if the input is short, or the file path is deep, you're not going to see anything useful. You forget what you selected and have not idea what you're about to upload. "Wait, did I upload a picture of my face or something less professional?"

Let's make it better.

The key is having an image preview that gets shown before the user needs to commit to saving it. So we ditch the upload button in favor of a save button. Now when a file is selected via the file section input, some AJAX kicks in. The image is processed server side and a thumbnail is loaded onto the existing page.

Doesn't that feel so much better? We now have a visual representation (imagine that) of the image we selected.

This is particularly useful in larger forms when many fields will be submitted with a single action. It allows the user to review the form before pressing save and see what image (or images) they selected.

How it's done

Curious how this is done? Here's the code.

We can use a standard HTML form. We'll include that as well as an image preview area.

<div id="upload-area">
	<div id="preview">
		<img width="100px" height="100px" src="/images/icons/128px/zurb.png" id="thumb">
	</div>

	<form action="/playground/ajax_upload" id="newHotnessForm">
		<label>Upload a Picture of Yourself</label>
		<input type="file" size="20" id="imageUpload" class=" ">
		<button class="button" type="submit">Save</button>
	</form>
</div>

The action of the form should point somewhere the process the uploading of the image, regardless of the presence of JavaScript. You may also want to consider only appending the preview markup via JavaScript, as that won't work without JS.

You're going to need jQuery and the AJAX Upload jQuery plugin by Andrew Valums. Link them up, making sure jQuery is loaded first. Note that the AJAX Upload plugin does require some configuration and server side stuff to work. Check out that link for details.

<script src="/js/jquery.min.js" type="text/javascript"></script>
<script src="/js/ajaxupload.js" type="text/javascript"></script>

Here is the JavaScript we're going to add in its entirety.

$(document).ready(function(){

	var thumb = $('#thumb');	

	new AjaxUpload('imageUpload', {
		action: $('#newHotnessForm').attr('action'),
		name: 'image',
		onSubmit: function(file, extension) {
			$('#preview').addClass('loading');
		},
		onComplete: function(file, response) {
			thumb.load(function(){
				$('#preview').removeClass('loading');
				thumb.unbind();
			});
			thumb.attr('src', response);
		}
	});
});

Here's that in plain English:

  1. Attach plugin behavior to the file input
  2. Specify the action URL, appropriately pulling it from the action URL in the markup
  3. When a file is selected, immediately add a class of "loading" to the preview area. This class name, through CSS, hides the image (e.g. .loading img { display: none; } and applies a background image (a spinner)
  4. Upon AJAX success, remove the loading class and set the src of the image to the response URL that the plugin returns.

Preview Only

Note that the above code deals with the preview functionality only. The file section input still contains the proper file path. So when the user clicks the "Save" button, the form will still need to be processed and handled by whatever server side technology you have ready for that. So yes, you will be essentially uploading the image once (for the preview) and then uploading it again (to save it in a more permanent way).

When you are setting up/configuring the plugin, you'll set up a directory for a server side script to save uploaded images to. You might want to have that live at somewhere like /images/temp/. That way you know that anything uploaded to that directory is transient and can be cleaned out temporarily to keep the server clean. A empty-that-directory CRON job might be a good idea.

Demo

A working demo is available on ZURB's site, which also includes more written information. Because of the server side stuff needing to happen, a download unfortunately isn't practical.

View Demo

 

Wondering about other awesome techniques with CSS3 and JavaScript? Check out the ZURB Playground.

ZURB is a close-knit team of interaction designers and strategists that help companies design better products & services. Since 1998 ZURB has helped over 75+ clients including: Facebook, eBay, NYSE, Yahoo, Zazzle, Playlist, Britney Spears, among others.

Comments

  1. Thanks for the tips!

    Could you recommend me some kind of simple AJAX progress bar upload file script? It seems to be hard to find.

    Thanks!

    • Daniel
      Permalink to comment#

      Ajax upload bar is hard to find becose depends on the server side language youre using. If php, give a look at pecl APC.

      Else, there are some flash swf uploader, but i dont like flash so i wouldnt raccomand them ;)

    • You can google html5 upload progress, you’ll find it

    • Isaac Lovely
      Permalink to comment#

      I know this may seem a little lazy but couldn’t you just make an old fashioned animated GIF file and use AJAX to add the class ‘loading’, as it is in Chris’ code, which could have a CSS attribute that calls the load animation GIF file until the class is removed. This way won’t give any precise loading information but it does imply that something is happening.

    • yes, but i would recommend creating a small flash animation similar to a gif. In testing IE froze the gif animation.

    • I recommend to use any flash based uploader because that will make your life much easier. I recommend these two:

      jqUploader

      SWFUpload jQuery Plugin

      Nice thing about these uploaders is that they both have nice jQuery API :)

  2. Thanks for the remake of this dynamic script that makes our lives as developers much easier – not to mention really impresses our less savvy clients.

  3. Permalink to comment#

    Love the “Men In Black” reference.

    Great script!

  4. Very neat – but there’s just one slight problem with this approach.

    What if the user accidentally choose the wrong file/picture? Normally, you would be able to change that, but now, it get’s uploaded automagically.

    This get’s problamatic when the user doesn’t wait until the image is fully uploaded. Try it on the demo: Select one image and after that, another image and so on. All images will be queued and loaded/shown after each other (when they’re processed).

    If the user already “submits” before the “final image” is processed, which one will be used as avatar?

    Other than that, a great example of usability :) !

    • Nate
      Permalink to comment#

      This is one of the first things I noticed. I selected a ginormous picture…3mb…and while it was uploading verrrry slowly, I realized I had a smaller version of it already. The only solution I found was to refresh the page and start over.

      Definitely needs a “cancel” button somewhere in there.

  5. Bryant
    Permalink to comment#

    To further touch on what Marco is saying, the solution is one part of a larger puzzle. Even though this is great front-end solution, it fails to address how to handle this on the server side.

    You can make an assumption of what the “Save” button does and some of the DB queries it might set in motion, but you also need to take account for images that will be left on your server if multiple files are upload, or how to delete them if you intend to save only one.

    Maybe round 2 of this article :)

    • The AJAX Upload Plugin will save files to a directory, as I mentioned in the article, probably best to save it to a TEMP directory. Clicking the save button will save it, presumably, to a more permanent home. What the form actually uploads is whatever the file path currently is in the input.

      I don’t think it’s as confusing as it is being made out to be here.

    • Permalink to comment#

      I agree, it’s not hard to get around the delete issue.

      Once the user has saved it, you can keep the file name, and preview/thumbnail if you like, then add a delete radio (or whatever), for that photo.

      This has been the source of much pondering for me at my site – I still haven’t nailed it, but this demo helps.

      Tim

  6. Permalink to comment#

    I used this on a site but in Chrome it would say “File not chosen” even though i had selected one. Has this been resolved?

    • Hey Fiaz – Thanks for the inquiry. The plugin works, this display message is just a little confusing in Chrome. It’s a Chrome related issue. We’ll see what we can do improve this.

      Thanks for chiming in! How do you like our other ZURBplayground techniques?

      -Dmitry

  7. jez
    Permalink to comment#

    I have been looking for Ajax image up-loaders and even looked at the ZURB site, but I was more specifically looking for an upload with a resize, crop function — (there doesn’t seem to be any code around the web)

    For the average Joe on the web (maybe that’s me?) it isn’t clear that the image isn’t saved when it is previewed, you see the image on the page so assume it is uploaded?

  8. Alex
    Permalink to comment#

    Unfortunately it doesn’t work with Opera 10.53.

  9. Akshay
    Permalink to comment#

    If I am not mistaken it was there on Zurb before also, I guess I’ve seen it.

  10. Permalink to comment#

    A mootools alternative that also supports FF drag and drop: http://mootools.standupweb.net/dragndrop.php

  11. Permalink to comment#

    Slight issue/more of a question… no iPad or iPhone support for choosing a photo to upload through this method… My inital thought is adding an input field to the “New Hotness”, that will allow copy and paste of filename, but that won’t really solve the issue in a user friendly way (they’d have to email the photo to themselves and then go through the forwarding the email motions to get the filename access… anyone have a more elegant solution to this?

  12. Isn’t it better to use a technique where the file is uploaded using the hidden iframe method?

    You can still preview the image but, with a bit of server side scripting, you can keep this file on form submission without having to wait for the file to be uploaded for a second time (the server side scripting also needs to fall back if the form uploads a file normally as well).

    • If I was building it from scratch that is what I would try and do too. If the file has already been uploaded one via AJAX, clicking save should just trigger an action to move that file to the permanent location and be done with it.

  13. Mike
    Permalink to comment#

    With regards to the “cleanup issue”: have a DB consisting of temp file names and upload timestamps. On upload complete, write the temp file and timestamp to the DB. On submit, remove it from the DB. Have a cron script that runs daily/weekly that queries the uploads from the prior day/week and delete those files. These will be all the images that were uploaded and never submitted. Very, very simple script/db and quite effective.

  14. This is good info! I especially like the MIB reference.

    K

  15. Once you have submitted the form, the temporary preview file can be deleted via PHP or other server-side language.

  16. Permalink to comment#

    huh;) this article saved my life, great stuff specialy because its done with Ajax. Keep up the good work and b.r.!

  17. Balazs
    Permalink to comment#

    Here’s how I implemented it. I have four image upload boxes on my site, and as each one is clicked an image is automatically uploaded.

    My form doesn’t have any file inputs at all, I applied the ajax upload to an upload icon, and after the image is uploaded, I have a php script that creates a zoom cropped full version, and a 100×100 thumbnail in a temp folder. The thumbnail path is returned in the response variable, and I use that to update a thumbnail image in the form, and insert the the response into a hidden field. I then hide the upload icon and replace it with a delete icon. If the delete icon is clicked, I reset the thumbnail and clear out the hidden field and then hide the delete icon and show the upload icon.

    When the form is submitted, the receiving script then reads the hidden inputs and moves those images and thumbnails out of the temp folder into their permanent folder.

    I have a cron job running that checks the modification time of each file in the temp folder and compares it to the current time. If the difference is greater than 14400, I delete the file (4 hours old). I don’t just wipe the folder because I may end up deleting an image of a user who is still using the form. If it’s taking someone more than four hours to submit a form with less than 10 fields, they have bigger problems than their uploads disappearing.

    And for those who say I should have file inputs in case someone has javascript off – my site is a google maps mashup so if they don’t have javascript on, they can’t use my site anyways.

    My only question is, why, after the iframe upload is complete, does my status bar still show a progress bar even though all requests are complete?

    Thanks
    B

  18. serdar
    Permalink to comment#

    can i use this ui in asp.net ?

  19. I am using jUploadify in this project here (u can only see it if you are registered, in your profile page (german)) -> http://1click.at/23s6h1

  20. Is this work in google chrome ?

  21. Permalink to comment#

    Don’t think the demo works any more, haven’t tested the actual script myself yet. But all i ever see is a lovely photo of Chuck Norris, tested it in Chrome, Safari, Opera, IE7+8 on XP and 7 :)

  22. Here is another fun Ajax Thingy..

    HTML5 Ajax Website http://bit.ly/9hXmZt

  23. jmk
    Permalink to comment#

    thanks for helping me

  24. Wes
    Permalink to comment#

    Hi just to check if this works in IE, and can I also check the min version required for JQuery? Saw from the demo they are using 1.7.1; will it work if I am using jQuery 1.4.4?

  25. The page with the AjaxUpload plugin isn’t operational. Are there any other sources for that plug in?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".