[SalesForce] Uploading files with visualforce page and attached it the record row

I have a visualeforce page with a pageblocktable, and a link 'Add row' to add row, but how can I save this row as a record in my object! and attach a file to each column, for example 'Food Expenses' I have to upload the bill

Here is my VF:

<apex:page controller="AP005ManageListController" tabstyle="Expenses__c">
<apex:stylesheet value="{!URLFOR($Resource.styles, 'RHstyles.css')}"/>
<apex:form >
<apex:pageBlock title="Bulk Account Create">
<apex:pageblockSection title="Traveling Information" >
  <apex:pageBlockTable value="{!wrappers}" var="wrapper" id="wtable">
     <apex:column headerValue="Client">
        <apex:inputField value="{!wrapper.acc.Client__c}"/>
     </apex:column>
     <apex:column headerValue="Project">
        <apex:inputField value="{!wrapper.acc.Project__c}"/>
     </apex:column>
     <apex:column headerValue="Date">
        <apex:inputField value="{!wrapper.acc.Date__c}"/>
     </apex:column>
     <apex:column headerValue="Food/Meal Expenses">
        <apex:inputText value="{!wrapper.acc.Food_Expenses__c}"/>
     </apex:column>

     <apex:column headerValue="Phone Expenses">
        <apex:inputField value="{!wrapper.acc.Phone_Expenses__c}"/>
     </apex:column>
    <!-- <apex:column headerValue="File">
    <apex:inputFile value="{!wrapper.a.body}" filename="{!wrapper.a.name}"/>
    </apex:column>  -->
    </apex:pageblockSection>
     <apex:column headerValue="Action">
        <apex:commandButton value="Delete" action="{!delWrapper}" rerender="wtable">
           <apex:param name="toDelIdent" value="{!wrapper.ident}" assignTo="{!toDelIdent}"/>
        </apex:commandButton>
     </apex:column>

  </apex:pageBlockTable>
  <apex:commandButton value="Add Row" action="{!addRows}" rerender="wtable">
     <apex:param name="addCount" value="1" assignTo="{!addCount}"/>
  </apex:commandButton>

  <apex:commandButton value="Save" action="{!save}"/>

And my controller :

public class AP005ManageListController
 {
  public List<ExpenseWrapper> wrappers {get; set;}
  public List<AttachmentWrapper> attach{get; set;}
  public static Integer toDelIdent {get; set;}
  public static Integer addCount {get; set;}
  private Integer nextIdent=0;
  public AP005ManageListController()
{
 wrappers=new List<ExpenseWrapper>();
 attach= new List<AttachmentWrapper>();
 attach.add(new AttachmentWrapper());
 wrappers.add(new ExpenseWrapper(nextIdent++));
}
public void delWrapper()
{
 Integer toDelPos=-1;
 for (Integer idx=0; idx<wrappers.size(); idx++)
 {
 if (wrappers[idx].ident==toDelIdent)
{
 toDelPos=idx;
 }
 }
  if (-1!=toDelPos)
 {
  wrappers.remove(toDelPos);
 }
 }
    public void addRows() {
    for (Integer idx=0; idx<addCount; idx++){
    wrappers.add(new ExpenseWrapper(nextIdent++));
    }
    }
    public PageReference save()
    {
    List<Expense__c> expes=new List<Expense__c>();
    List<Attachment> att=new List<>(Attachment);
    for (ExpenseWrapper wrap : wrappers){
    for(AttachmentWrapper attWrap :attach ){
    att.add(attWrap.exp);
    }
     expes.add(wrap.exp);
  } 
      insert expes;
     return new PageReference('/' +   Schema.getGlobalDescribe().get('Expense__c').getDescribe().getKeyPrefix() + '/o');
      }
      public class ExpenseWrapper
      {
      public Expense__c exp{get; private set;}
      public Integer ident {get; private set;}

      public ExpenseWrapper(Integer inIdent)
      {
      ident=inIdent;
      exp=new Expense__c();
      }
}
public class AttachmentWrapper {
public Expense__c exp {get;set;}
public Attachment att {get;set;}
public AttachmentWrapper(Expense__c exp, Attachment att){
    this.exp = exp;
    if(att!= null){
        this.att = att;
    } else {
        this.att = new Attachment(parentId = this.att.Id);
    }
}
}
}

How can I put the 'upload file' button to upload a number of files and attached it to the rercord

Best Answer

You need to use a wrapper class to have both the Expense__c record and it's attachment record in the pageblocktable. Change your current wrapper to something like this:

public class ExpenseWrapper
{
        public Expense__c exp{get; private set;}
        public Attachment att {get;set;}
        public Integer ident {get; private set;}

        public ExpenseWrapper(Integer inIdent)
        {
            ident=inIdent;
            exp=new Expense__c();
            att=new Attachment();
        }
}

The list you display in the pageblocktable should then be a List<ExpenseWrapper> instead of a List<Expense__c>.

Then create a file upload button inside the pageblocktable like this:

<apex:pageBlockTable value="{!wrapperList}" var="wrapperRecord" >           
    <apex:column headerValue="Date">
        <apex:inputField value="{!wrapperRecord.m.Date__c}"/>
    </apex:column>
    <apex:column headerValue="Food/Meal Expenses">
        <apex:inputField value="{!wrapperRecord.m.Food_Expenses__c}"/>
    </apex:column>
    <apex:column headerValue="Phone Expenses">
        <apex:inputField value="{!wrapperRecord.m.Phone_Expenses__c}"/>
    </apex:column>              
    <apex:column headerValue="File">
        <apex:inputFile value="{!wrapperRecord.a.body}" filename="{!wrapperRecord.a.name}"/>
    </apex:column>          
</apex:pageBlockTable>  

Lastly, don't forget to update both the Expense__c records and the Attachments in your save method (updating the parentId on the Attachment records with the new Expense__c id's before saving them). Something like this:

public PageReference save()
{
    List<Expense__c> expes=new List<Expense__c>();
    List<Attachment> attToInsert=new List<>(Attachment);
    for (ExpenseWrapper wrap : wrappers){
        expes.add(wrap.exp);
    } 
    insert expes;

    Integer counter = 0;
    for(Expense__c exp : expes){

        if(exp.Id != null){
            if(wrappers[counter].att != null){
                wrappers[counter].att.parentId = exp.Id;
                attToInsert.add(wrappers[counter].a);
            }
        }
        counter++;
    }
    insert attToInsert;

    return new PageReference('/' +   Schema.getGlobalDescribe().get('Expense__c').getDescribe().getKeyPrefix() + '/o');
}