[SalesForce] apex:inputFile can’t be used in conjunction with an action component when deleting a row

When working on a visualforce page, I encountered this error:

"apex:inputFile can not be used in conjunction with an action component, apex:commandButton or apex:commandLink that specifies a rerender or oncomplete attribute"

This happens when I'm trying to delete a row from PageBlockTable.

In the visual source page, i first half of the screen i have component to upload the documents, below which i'm displaying the document. when i'm trying to delete the document in a particular row i'm getting the above issue.

enter image description here

Visualforce Page

<apex:page controller="FileUploadController" sidebar="false" showHeader="false">
   <apex:form enctype="multipart/form-data" id="docform">
    <apex:pageBlock title="Document" id="docpb">
        <table>
            <tr>
                <td> <apex:outputLabel value="Doc Code" for="docCode"/></td>
                <td>
                    <apex:selectList value="{!docCode}" id="docCode" multiselect="false" size="1">
                        <apex:selectOptions value="{!docCodes}"/>
                    </apex:selectList>
                </td>
            </tr>

            <tr>
                <td>
                     <apex:outputLabel value="File" for="file"/>
                </td>
                <td>
                    <apex:inputFile value="{!document.body}" filename="{!document.name}" id="file"/>
                </td>
            </tr>
            <tr>
                <td colspan='1'>
                    <apex:commandButton action="{!upload}" value="Save"/>
                </td>
            </tr>        
       </table> 
    </apex:pageBlock>
    <apex:pageBlock title="Documents" id="dpb">

        <apex:pageBlockTable value="{!documentList}" var="documentItem" id="documentTable">
            <apex:column headerValue="Document Code">
                <apex:outputField value="{!documentItem.Name}"/>
            </apex:column>
            <apex:column headerValue="Date">
                <apex:outputField value="{!documentItem.LastReferencedDate}"/>
            </apex:column>
            <apex:column headerValue="User">
                <apex:outputField value="{!documentItem.AuthorId}"/>
            </apex:column>
             <apex:column headerValue="Delete">
                 <apex:commandLink action="{!deleteDocument}" reRender="dpb"> 
                      <apex:image url="{!URLFOR($Resource.packaging, 'images/deleteicon.gif')}" />
                      <apex:param value="{!documentItem.Name}" name="docCodeParam" />
                 </apex:commandLink>
            </apex:column>
        </apex:pageBlockTable> 
        <br/>

    </apex:pageBlock>
  </apex:form>
</apex:page>

Apex Code:

public class FileUploadController {

    public PageReference deleteDocument() {

        String docCodeParam = apexpages.currentpage().getparameters().get('docCodeParam');

        System.debug('delete a document :: '+docCodeParam);

        return null;
    }


   public String docCode {get; set;}

   public List<Document> documentList {get; set;}

   public List<Folder> folderList {get; set;}

   public Document document {
        get {
          if (document == null)
            document = new Document();
          return document;
        }
        set;
   }

   public FileUploadController(){


      folderList = [SELECT Id,Name FROM Folder WHERE Name = 'IMAGE DOCS' ];

      if(folderList!=null && !folderList.isEmpty()){

          Folder folder = folderList.get(0);

          documentList = [SELECT Name , Type , Url, AuthorId, Body , 
                            LastReferencedDate , LastViewedDate, FolderId  FROM Document  
                            document where FolderId IN:folderList ];

      }


  }

  public PageReference upload() {

     Boolean isSuccess = true;

     if(folderList!=null && !folderList.isEmpty()){

          Folder folder = folderList.get(0);
          document.AuthorId = UserInfo.getUserId();
          document.FolderId =  folder.Id;// put it in running user's folder
          document.name = docCode+'-'+document.name;
    }

    try {

      insert document;

    } catch (DMLException e) {

      isSuccess = false;
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading file'));

    } finally {

      document.body = null; // clears the viewstate
      document = new Document();

    }

    if(isSuccess){
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,'File uploaded successfully'));
    }

    return null;
  }

  public List<SelectOption> getDocCodes(){

     List<SelectOption> docCodeList = new List<SelectOption>();
     docCodeList.add(new SelectOption('','')); 
     docCodeList.add(new SelectOption('PHOTO','PHOTO - PHOTO')); 
     docCodeList.add(new SelectOption('DOC','DOC - DOC')); 

     return docCodeList;
  } 

}

Best Answer

You can use an actionRegion to define a scope for a commandButton or commandLink. This is sufficient to allow inputFile to happily co-exist with reRender attributes. Note that the actionRegion must contain all the information necessary to update the page, because only the components inside the actionRegion is processed by the server. Here's a simple example:

Controller

public with sharing class renderFile {
    public transient Blob fileBody { get; set; }
    public String contentType { get; set; }
    public String fileName { get; set; }
    public string[] items { get; set; }

    public renderFile() {
        items = new string[0];
    }

    public void save() {
        Document d = new Document(FolderId=UserInfo.getUserId(), Name=fileName, Body=fileBody, ContentType=contentType);
        insert d;
        items.add('Uploaded '+d.Name+' as ID '+d.Id);
    }
    public void reRender() {
        items.add('Item: '+(items.size()+1));
    }
}

Page

<apex:page controller="renderFile">
    <apex:form id="form">
        <apex:pageBlock >
            <apex:pageBlockButtons location="bottom">
                <apex:actionRegion id="area51" renderRegionOnly="false">
                    <apex:commandButton value="Something" reRender="form" action="{!reRender}"/>
                </apex:actionRegion>
                <apex:commandButton value="Save" action="{!save}"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection >
                <apex:repeat value="{!items}" var="value">
                    <apex:outputText >{!value}</apex:outputText>
                </apex:repeat>
                <apex:inputFile contentType="{!contentType}" fileName="{!fileName}" value="{!fileBody}" />
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Related Topic