Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Ajax

Grails+Dojo Ajax File Upload

5.00/5 (2 votes)
14 Apr 2009CPOL2 min read 26.3K  
Grails+Dojo Ajax file upload

I'm currently working on a Grails application with a requirement for uploading product images, which are subsequently resized into thumbnails of various sizes for different shopping screens. Since it took a bit of doing to get this done, I thought I'd post my solution here in case anyone could benefit from it.

First, to set the stage, I've upgraded the application all the way to the newly released Grails 1.1.

To start off, I naively attempted to use the built-in Prototype library to do the upload with a simple <g:submitRemote/> tag. You might have guessed that this didn't work at all. Continuing to learn the hard way (without reading the manual I might add), I submitted this as a bug to the Grails project. Graeme ever so politely informed me that this was known and expected behavior, as Prototype doesn't support such a thing. However, it was Graeme that also tipped me off to try Dojo.

So, continuing down this path, I proceeded to install the Grails Dojo plugin. Once this is done, a <g:javascript library="dojo"/&gt is supposedly all that is required to convert your Ajax calls from Prototype to Dojo. This turned out to not be the case for me, with JavaScript errors popping up all over the place, not the least of which was that dojo.js seemed to be installed in an unexpected location via the plugin. The hacker in me simply copied this to the expected location and moved along. However, as I attempted to work with Dojo's file upload support, I discovered that the version of Dojo shipped with the plugin seemed at first glance to be way behind. Frustrated by this, I went ahead and stripped the Dojo plugin out and installed the latest version available (at this writing 1.2.3), and set about to develop my solution.

Here goes:

1. Add the necessary Dojo dependencies to your GSP

JavaScript
<script type="text/javascript" src="${createLinkTo(dir: 'js/dojo', file: 'dojo.js')}"
   djConfig="parseOnLoad:true, isDebug:true"></script>
<g:javascript>
   dojo.require("dojo.io.iframe");
</g:javascript>

2. Write a function using dojo.io.iframe to send the form

JavaScript
function submitForm() {
   dojo.io.iframe.send({
      form: 'uploadProductImageForm',
      load: function (data) {
         dojo.byId('productImage').innerHTML = data;
      }
   });
}

3. Create the file upload form

XML
<g:form name="uploadProductImageForm" 
method="post" action="uploadProductImage"
    enctype="multipart/form-data">
   <input type="hidden" name="id" value="${productInstance?.id}"/>
   <input type="file" name="newProductImage"/>
   <span class="button"><input class="add" 
   type="button" name="uploadImage"
    value="Upload Image" onclick="submitForm()"/></span>
</g:form>

4. Create the controller method

JavaScript
def uploadProductImage = {
   def f = request.getFile('newProductImage')
   if (!f.empty) {

   def imagePath = grailsApplication.config.store.productImages.location

   //Create unique name for this image set based on current timestamp
   def name = "image" + new Date().getTime()

   //Store the file
   def file = new File("${imagePath}/${originalFilename}")
   f.transferTo(file)

   //Do some image processing (resizing, etc.)
   ...

   //Dojo requires returning the result nested in an HTML document containing
   //a body and textarea tag. Do this with
   //Groovy's built-in MarkupBuilder

   def writer = new StringWriter()
   def xml = new MarkupBuilder(writer)

   xml.html {
     body {
       textarea {
         img(src: resource(dir: grailsApplication.config.store.productImages.webPath,
            file: product.mediumImage.name), width: '250')
       }
     }
   }

   render writer.toString()
   }
   else {
      flash.message = 'file cannot be empty'
      redirect(action: show)
   }
}

And there you have it! Let me know what you think of this solution. It definitely works for me. You will notice that I didn't include an upload progress bar - I'll be doing this in a future iteration of the project. Cheers!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)