views:

46

answers:

3

Imagine this simple form for uploading a file:

<form action="upload" enctype="multipart/form-data">
    <input type="text" name="name"/>
    <input type="file" name="file"/>
    <input type="submit"/>
</form>

If there is some error (can't copy file, name is not correct...) submitting the form, it must return to the same page, but the file I've selected will be lost. In a large form with several fields that must be validated server side can be very annoying if the user have to select files every time.

Thinking about it, I've find a couple of possible solutions:

  • Submit form as an ajax request, then go to the next page only if validation is correct. The problem is I must implement something to put every validation error in its place instead of using MVC's features (Spring MVC form tags, in my case).

  • Submit form. If there is an error, send a page with a "history.back()" in javascript. My file will be there again, but I have no easy way to show validation messages.

I think both solutions are very very clumsy. But selecting the files every time there is a validation error isn't a good solution too.

What do you think? Which solution is better? Is there any good one (preferably without javascript)?

Thanks.

Note: I'm using Spring MVC 3

+2  A: 

Using AJAX won't work, as it can't deal with file uploads.

What about another alternative: Submit the form into an (invisible?) IFRAME:

<form target="iframe_name_here" ........

<iframe id="iframe_name_here"></iframe>

you could then use JavaScript to send a "success" event from within the page in the iframe, for example.

I think that should even keep the selected file in place if the upload goes wrong.

Pekka
Well. when I said Ajax, I was actually thinking about this kind of solution, because is what Ajax frameworks do. The problem, as I said, is having to put every validation message in its place, in Javascript.
Sinuhe
A: 

I'm not sure what type of validation you plan on doing but would breaking it out into separate pages, like a wizard, with the file upload being the last step, work?

With Javascript, you can use the iframe method that Pekka suggested. Most of the Ajax file uploaders that I've seen work that way.

Marcus Adams
Sadly, I can't do that :(
Sinuhe
+1  A: 

It's true that the file field will be lost since there's no way to prefill the input type="file" field in HTML. This is a security restriction to avoid jokers with forms like this:

<form name="upload" action="upload" method="post" enctype="multipart/form-data">
    <input type="file" value="c:/passwords.txt"><input type="submit">
</form>
<script>document.upload.submit()</script>

Your only resort is to submit the form in the background so that the page with the original form stays open. In other words: Ajax. There are several JavaScript libraries available for this task, for example jQuery Form plugin. It's then basically as easy as

$('#formId').ajaxForm();

(yes, it will work with file uploads as well, this plugin transparently goes to "iframe mode" then)

But since you're using Spring MVC which doesn't support ajaxical requests out of the box, you'll have to create a custom ViewResolver in the server side to let it seamlessly work with ajaxical stuff. You can find here a nice blog which describes that in detail.

BalusC
Well I think you're right except for the last paragraph. I don't like this solution, specifically to let the AjaxView serialize the model freely (without excludes). I think is easier to create the JSON (if you really need a JSON) in the Controller (maybe with some helper) or the JSP (yeah, a little clumsy, but useful in some cases).
Sinuhe