+ Start a Discussion
AndrewXAndrewX 

Possible bug in <apex:inputFile> component

I have a small form with an <apex:inputFile> in which I am trying to upload an attachment.

 

<apex:form id="form_Upload">
<apex:inputFile id="file_File" value="{!fileBody}" filename="{!fileName}" size="60"/>
<apex:commandButton id="button_Upload" value="Upload"

onclick="if (!validateUploadForm())return" action="{!processUpload}" />
</apex:form>

 

Because I have an onclick JavaScript handler specified for the commandButton, the "action" never occurs (i.e. the Ajax call that would normally be inserted into the onclick never gets inserted) so my HTML source says ony onclick="if (!validate etc...)".

 

I've found that the way to solve this is to add a rerender="" attribute to the commandButton. Since I don't need to rerender anything, I created an empty outputPanel, and added that to the rerender of the commandButton like this:

 

<apex:commandButton rerender="panel_Empty" ... />

 

Well that fixed the problem, because now the generated onclick for the commandButton called my JavaScript onclick then called the Ajax submit method. So far so good....

 

The problem is that when I run this page, I get a runtime error that says that the <apex:inputFile> cannot be used with a commandButton that specifies a rerender attribute.

 

Is this deliberately like this, or is it a bug?

 

Thanks,

Andrew

 

 

Best Answer chosen by Admin (Salesforce Developers) 
rtuttlertuttle

Nevermind, figured it out.  For anyone else out there looking for the solution here is how I managed it.

 

Create a temporary attachment object,   instantiate it in the constructor

Create an iframe, make it display: none, height: 0px, width: 0px, border: 0px, etc...

Create a form for the attachment, set the target to the iframe, map it to values inside the current controller, and an action to do the attachment.

Create the function to perform the attachment, reinstantiate the temporary attachment object (if they can upload more afterward) then have it return a page reference to a new page.

Create the new page with a javascript block only, inside it call 'parent.refreshAttachments();'

Create a second form for an actionFunction

Create the actionfunction inside the second form and name it "refreshAttachments", have it call a reloadattachments function in the controller to pull the data from the database, and rerender the attachments list (inside a pageblock etc)

 

Note the second form is bold.  You cannot put the actionfunction inside the same form as the inputfile or it will throw the error for trying to rerender while doing fileupload.

 

Hope this helps someone.

 

Message Edited by rtuttle on 05-11-2009 02:26 PM

All Answers

jwetzlerjwetzler

I was hoping that error message would be an indicator that it's deliberate.  It's actually not a trivial problem to solve -- creating a form that can do file uploads in an ajax request.  Not just in Visualforce but in HTML/javascript.  If you search around the internet I found various solutions that involve posting into a hidden iframe and other various magic that make it doable so you might want to check that out.

 

It's definitely on our backlog to do this automatically for you, but until that gets implemented we didn't want people specifying rerender targets and then wondering why their file upload wasn't working, so we put the error message in. 

rtuttlertuttle

Jill, I have read a few of your posts regarding the trick to get around this.  I tried the invisible iframe method  and push it to another page, but ran into an issue trying to take raw binary data from POST and put it into a blob (attachment.body).  Is there a way to access the actual post data to do this or am I missing something simpler here?  getParameters doesn't seem to be able to pull in the data.

rtuttlertuttle

Nevermind, figured it out.  For anyone else out there looking for the solution here is how I managed it.

 

Create a temporary attachment object,   instantiate it in the constructor

Create an iframe, make it display: none, height: 0px, width: 0px, border: 0px, etc...

Create a form for the attachment, set the target to the iframe, map it to values inside the current controller, and an action to do the attachment.

Create the function to perform the attachment, reinstantiate the temporary attachment object (if they can upload more afterward) then have it return a page reference to a new page.

Create the new page with a javascript block only, inside it call 'parent.refreshAttachments();'

Create a second form for an actionFunction

Create the actionfunction inside the second form and name it "refreshAttachments", have it call a reloadattachments function in the controller to pull the data from the database, and rerender the attachments list (inside a pageblock etc)

 

Note the second form is bold.  You cannot put the actionfunction inside the same form as the inputfile or it will throw the error for trying to rerender while doing fileupload.

 

Hope this helps someone.

 

Message Edited by rtuttle on 05-11-2009 02:26 PM
This was selected as the best answer
colemabcolemab

jwetzler wrote:

 

It's definitely on our backlog to do this automatically for you, but until that gets implemented we didn't want people specifying rerender targets and then wondering why their file upload wasn't working, so we put the error message in. 


Must be some backlog since your comment was made "more than one year ago" (lol @ idea exchange removing dates) and this still isn't in place.   Web 2.0 anyone?  I mean seriously, google did this in gmail years before your comment.