function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Zach Gavin DelacroixZach Gavin Delacroix 

Working with Collection (List) in VisualForce

Hi Experts,

I'm trying to learn VisualForce and it seems that I'm stuck with using Collection.

I have <apex:inputField> and <apex:commandButton>, what I want to do is add the value I type in the inputField when I click the commandButton.

Can anyone please give me an Idea of the correct syntax?

Here's the code I created so far that is not working as expected.
<apex:page controller="MultiAccountInsertController" sidebar="false">
  
  <apex:pageBlock title="Enter Account Name">
      <apex:form >
          <apex:inputText value="{!acc.name}"/>
          <apex:commandButton value="Add Account" action="{!addAccount}"/>
      </apex:form>
  </apex:pageBlock>  
  
  <apex:pageBlock title="List of Accounts to Save">
  	To be continued...
  </apex:pageBlock>
</apex:page>
CLASS
 
public class MultiAccountInsertController {
    
    Public account acc{get;set;}
    List<account> AccountList; 

    public MultiAccountInsertController(){
        acc = new account();
        AccountList = new List<account>();
    }
    public void addAccount(){
		AccountList.add(acc);
        
        //Check value of the AccountList in Debug
        for(integer i=0;i<AccountList.size();i++){
           system.debug(AccountList[i].name); 
        }
    }
    public List<account> getViewAccounts(){
        return AccountList;
    }
}

When I run Click the button, the result goes like below.

09:41:52:039 USER_DEBUG [13]|DEBUG|A
09:41:52:039 USER_DEBUG [13]|DEBUG|B

The result I want should look like below because I typed "A" first then pressed the button, then Typed B then pressed the button. So Everytime I type value in the Text Field, I want to add it as a value in my List.

09:41:52:039 USER_DEBUG [13]|DEBUG|A
09:41:52:039 USER_DEBUG [13]|DEBUG|B

NOTE: I'm using Account for testing, when I have this working, I'll try to work on inserting the Records from the List of Accounts (But don't answer this part coz I want to figure it our my self first :D )

Thanks for the help!
Best Answer chosen by Zach Gavin Delacroix
pconpcon
This is because when you do a .add you are adding a "pointer" to the same account.  So when you update the account in your visualforce controller you update the same version and therefore they all equal.  You can use the clone() method

Page
<apex:page controller="MultiAccountInsertController" sidebar="false">
    <apex:pageBlock title="Enter Account Name">
        <apex:form >
            <apex:inputText value="{!acc.name}"/>
            <apex:commandButton value="Add Account" action="{!addAccount}"/>
        </apex:form>
    </apex:pageBlock>  
    
    <apex:pageBlock title="List of Accounts to Save">
        <apex:pageBlockTable value="{!viewAccounts}" var="acct">
            <apex:column value="{!acct.Name}" />
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

Controller
public class MultiAccountInsertController {
    
    Public account acc{get;set;}
    List<account> AccountList; 

    public MultiAccountInsertController(){
        acc = new account();
        AccountList = new List<account>();
    }
    public void addAccount(){
		AccountList.add(acc.clone());
        
        //Check value of the AccountList in Debug
        for(integer i=0;i<AccountList.size();i++){
           system.debug(AccountList[i].name); 
        }
    }
    public List<account> getViewAccounts(){
        return AccountList;
    }
}

 

All Answers

pconpcon
This is because when you do a .add you are adding a "pointer" to the same account.  So when you update the account in your visualforce controller you update the same version and therefore they all equal.  You can use the clone() method

Page
<apex:page controller="MultiAccountInsertController" sidebar="false">
    <apex:pageBlock title="Enter Account Name">
        <apex:form >
            <apex:inputText value="{!acc.name}"/>
            <apex:commandButton value="Add Account" action="{!addAccount}"/>
        </apex:form>
    </apex:pageBlock>  
    
    <apex:pageBlock title="List of Accounts to Save">
        <apex:pageBlockTable value="{!viewAccounts}" var="acct">
            <apex:column value="{!acct.Name}" />
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

Controller
public class MultiAccountInsertController {
    
    Public account acc{get;set;}
    List<account> AccountList; 

    public MultiAccountInsertController(){
        acc = new account();
        AccountList = new List<account>();
    }
    public void addAccount(){
		AccountList.add(acc.clone());
        
        //Check value of the AccountList in Debug
        for(integer i=0;i<AccountList.size();i++){
           system.debug(AccountList[i].name); 
        }
    }
    public List<account> getViewAccounts(){
        return AccountList;
    }
}

 
This was selected as the best answer
Zach Gavin DelacroixZach Gavin Delacroix
Thanks a lot @pcon,

That worked as expected.

Just one more question though, am I doing the correct approach? or is there any other way to do it?

Can you give me advice what to read if I'm going for these kinds of pages?

Thanks
pconpcon
What you're doing is fine.  Personally I would make a minor modification to the page / controller to make it a little better user experience.

Page
<apex:page controller="MultiAccountInsertController" sidebar="false" id="thePage">
    <apex:pageBlock title="Enter Account Name">
        <apex:form >
            <apex:inputText value="{!account.name}"/>
            <apex:commandButton value="Add Account" action="{!addAccount}" reRender="thePage" />
        </apex:form>
    </apex:pageBlock>  
    
    <apex:pageBlock title="List of Accounts to Save">
        <apex:pageBlockTable value="{!accounts}" var="acct">
            <apex:column value="{!acct.Name}" />
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>
Updated the command button to re-render the whole page.  Instead of having the page "reload"  This give you more control.

Controller
public class MultiAccountInsertController {
    public Account account {
        get;
        set;
    }

    List<Account> accounts {
        get;
        set;
    } 

    public MultiAccountInsertController() {
        this.account = new Account();
        this.accountList = new List<Account>();
    }

    public PageReference addAccount() {
        this.accountList.add(this.account.clone());
        this.account = new Account();

        return null;
    }
}
I've simplified the controller a little bit, reformatted it a little bit and then "reset" the account after it's been added to make it so the form is ready to be used.
 
Zach Gavin DelacroixZach Gavin Delacroix
Thank you so much for answering all my questions and for the great advise. This is a big help for learning VisualForce.

Appreciate it!