1

I am building an Add Account page, and have 3 questions about form entry:

  1. When entering a new account, how do you refresh the input form fields, so that another value can be entered? I have tried refreshing the section, and the fields unsuccessfully.
  2. The record insert seem to stop after 1 entry, occasionally 2. Is this down to bad code? or is it more about traffic - trying to create multiple records could be risky?
  3. The class that I am writing duplicates the SOQL query, how would I write this more efficiently?

Thanks

HTML:

<apex:page docType="html-5.0" controller="addAccountModalController">

<c:overlay />

<apex:form id="inputForm" >
<div id="newAccount">
<div class="modalSubheading">Account Details</div>
<table> 
    <tr>
        <td style="padding-right:10px;">
            <apex:inputField id="accountName" styleClass="form-control" value="{!addAccount.name}" html-placeholder="Account Name"/>
        </td>
        <td style="padding-left:10px;">
            <apex:inputField id="primaryEmail" type="email" styleClass="form-control" value="{!addAccount.Primary_Email__c}" html-placeholder="Email Address"/>
        </td>
    </tr>
</table>

<table style="width:100%;margin-bottom:20px;">
    <tr>
        <td>
            <apex:commandButton styleClass="btn btn-success pull-right" onclick="addAccount();" onComplete="addAccount" value="Add Account"/>
                <apex:actionFunction name="addAccount" action="{!addAccount}" status="overlayStatus" reRender="outputForm,inputForm"/>
        </td>
    </tr>
</table>
</div>
</apex:form>

<apex:form id="outputForm">
<div class="modalSubheading">Existing Accounts</div>
<table>
    <thead class="tableHead">
        <tr>
            <td>Name</td>
            <td>Primary Email</td>
            <td>Action</td>
        </tr>
    </thead>
    <apex:repeat value="{!allAccounts}" var="acc">
        <tr>
            <td><apex:inputField value="{!acc.name}" styleClass="form-control"/></td>
            <td><apex:inputField value="{!acc.Primary_Email__c}" styleClass="form-control"/></td>
            <td>
                <apex:commandlink action="{!delAccount}" value="Remove" rerender="outputForm" status="overlayStatus" > 
                    <apex:param name="accId" value="{!acc.Id}" assignTo="{!selectedAccId}" />
                </apex:commandlink>
            </td>
        </tr>
    </apex:repeat>
</table>

<table>
    <tr>
        <td>
            <apex:commandButton styleClass="btn btn-save pull-right" action="{!save}" status="overlayStatus" rerender="accountsList" value="Save"/>
        </td>
    </tr>
</table>
</apex:form>

</apex:page>

Class:

public class addAccountModalController {

public Account addAccount {get;set;}
public Id selectedAccId {get;set;}
public list <Account> allAccounts {get;set;}

    public addAccountModalController(){

        addAccount = new account(
        //recordType.id = '01290000001GbSj', 
        //recordType.Name = 'Entity'
        );
        allAccounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];
    }

public PageReference addAccount() {
    try {
        insert(addAccount);
        allAccounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating Account.'));
    }
    return null;
}

public PageReference save() {
    try {
        update allAccounts;
        allAccounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
    }
    return null;
}

public pageReference delAccount() {
    try {
        delete new Account(Id = selectedAccId);
        allAccounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
    }
    return null;
}
}

Image:

enter image description here

Using only VF tags:

<apex:form >
<apex:pageBlock id="inputForm" >
    <apex:inputField id="accountName" styleClass="form-control" value="{!addAccount.name}" html-placeholder="Account Name"/>
    <apex:inputField id="primaryEmail" type="email" styleClass="form-control" value="{!addAccount.Primary_Email__c}" html-placeholder="Email Address"/>
    <apex:commandButton styleClass="btn btn-success pull-right" onclick="addAccount();" onComplete="addAccount" value="Add Account"/>
        <apex:actionFunction name="addAccount" action="{!addAccount}" status="overlayStatus" reRender="outputForm,inputForm"/>
</apex:pageBlock>
</apex:form>


<apex:form >
<apex:pageBlock id="outputForm">
<apex:pageBlockTable value="{!allAccounts}" var="acc">
    <apex:column value="{!acc.name}" styleClass="form-control"/>
    <apex:column value="{!acc.Primary_Email__c}" styleClass="form-control"/>
    <apex:column >
        <apex:commandlink action="{!delAccount}" value="Remove" rerender="outputForm" status="overlayStatus" > 
            <apex:param name="accId" value="{!acc.Id}" assignTo="{!selectedAccId}" />
        </apex:commandlink>
    </apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>

4 Answers 4

1

Let's deal with point3 for starters. Remove those queries from the action methods.

The class that I am writing duplicates the SOQL query, how would I write this more efficiently?

public list <Account> allAccounts {
    get{
           return [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate 
                      FROM Account ORDER by createdDate DESC LIMIT 5];
    private set;
}

When the page is displayed initially or upon ajax refresh, VF will request the value of merge field {!allSAccounts} on this line

<apex:pageBlockTable value="{!allAccounts}" var="acc">

by invoking the getter in the controller. The getter returns the latest 5 Accounts. This is a pretty standard VF pattern. Let the action methods do work and then, when the action method returns (in an AJAX refresh by returning null or being a void method), the getters are invoked and the page gets current values.

Pages do AJAX refreshes by the presence of the rerender attribute on a commandButton, commandLink, actionSupport, actionFunction

You don't need two forms, one should suffice.

It is worth reading VF in Practice for many good examples of standard VF design patterns.

It is really worth reading the Visualforce Order of Execution for postback requests which is what your commandButton is doing, as well as Visualforce Order of Execution for Get requests which is what happens when the page is initially displayed.

1
  • Thanks for this, there was a missing right curly bracket, but that has done the trick... Commented Jun 9, 2016 at 5:39
0

I am confused with your code. Please refer below points:

  1. Better to use apex:pageBlockTable rather than html table as it easy to maintain and you can easily rendered and refresh the table content when action function has completed. For this you need to use rendered attribute in <apeex:actionFunction ... />.

  2. I didn't find any insert(addAccount) method where you actually do insert operation. Please add this code so that it easy to know difficulty you face.

  3. For reusability of SOQL, you can write one private method with below signature:

private List<Account> getAccounts() { List<Account> accounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5]; return accounts; } Now you call this function wherever it requires. It resolve duplicate problem.

Hope it helps you :)

5
  • Thanks for your reply! 1. The input is going on a highly customised modal, where i would rather keep the table for classes, styles and JS interactions. 2. I have added the full page to the HTML section above. 3. Thanks for this! Commented Jun 9, 2016 at 3:02
  • Does it helps you?1. You can also apply classes, styles on pageBlockTable. 2. This method you have written in controller in save() method, I didn't find this in controller. Commented Jun 9, 2016 at 3:03
  • I am having trouble fitting in the function, in my pasted code (question 3). I already query the fields, I need to use this query again? Or is what you posted an addition? either way, how do i build the variable in to the save/insert functions? Commented Jun 9, 2016 at 3:10
  • If you need to reuse the query then you fire it in constructor and use the same variable of List<Account> everywhere you use. But I fear that whenever you perform CRUD operation you doesn't get the updated list. For that you need to follow the third step that I refer. So like in save() method after update statement, you called getAccounts() method that perform SOQL and return you the result. Commented Jun 9, 2016 at 3:34
  • I have added the same detail, but only using VF tags. The same issues occur. 1. Adding a new account - Account name still remains, regardless of rerender. 2. Adding new accounts stops after 1 or 2 entries... Commented Jun 9, 2016 at 3:45
0

Question 3, working...The original class, with @cropredy's adjustment...

public class addAccountModalController {

public Account addAccount {get;set;}
public Id selectedAccId {get;set;} 
//public list <account> allAccounts {get;set;}

public list <Account> allAccounts {
    get{
       return [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate 
                  FROM Account ORDER by createdDate DESC LIMIT 5];
       }
    private set;
}

    public addAccountModalController(){

        addAccount = new account();
        //allAccounts = [SELECT id,Name,Primary_Email__c,recordType.id,recordType.Name,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];
    }

public PageReference addAccount() {
    try {
        insert(addAccount);
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating Account.'));
    }
    return null;
}

public PageReference save() {
    try {
        update allAccounts;
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
    }
    return null;
}

public pageReference delAccount() {
    try {
        delete new Account(Id = selectedAccId);
    } catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
    }
    return null;
}
}

Thanks

2
  • If this adjusted class is the correct answer then mark it answer else you should add this to the comments against the answer of Cropredy.
    – Mahmood
    Commented Jun 9, 2016 at 6:59
  • @Mahmood This doesn't answer the post, just part of it. When the other questions have been fixed up, I will post the full answer and mark it, thanks. Commented Jun 9, 2016 at 7:15
0

I have tried your code at my developer edition to solve the issues.

Only thing you need to change is the query written in getAccountsList, you need to include recordType.id,recordType.Name in the query.

Also, if possible use only one form in Visualforce page.

Now the rendering issues has been solved.

Controller class code as been optimized.

HTML:

<apex:form><apex:pageBlock id="inputPanel">
<apex:pageBlockSection>
<apex:inputField id="accountName" styleClass="form-control" value="{!objAccount.name}" html-placeholder="Account Name"/>
<apex:inputField id="primaryEmail" type="email" styleClass="form-control" value="{!objAccount.Primary_Email__c}" html-placeholder="Email Address"/>
<apex:actionFunction name="addAccountFn" action="{!addAccount}" status="overlayStatus" reRender="inputPanel,outputForm"/>
<apex:commandLink onclick="addAccountFn();return false;" style="text-decoration:none">
   <apex:commandButton value="addAccount"/>
</apex:commandLink> 
</apex:pageBlockSection></apex:pageBlock></apex:form><apex:form id="outputForm">
<apex:pageBlock title="Existing Accounts"> 
        <apex:pageBlockTable value="{!accountsList}" var="acc"   columnsWidth="30%,30%,40%" id="accDetail">
            <apex:column headerValue="Name">
                <apex:inputField value="{!acc.name}"/>
            </apex:column>
            <apex:column headerValue="Primary Email">
                <apex:inputField value="{!acc.Primary_Email__c}"/>
            </apex:column>
            <apex:column headerValue="Action">
                <apex:commandlink action="{!delAccount}" value="Remove" rerender="outputForm" status="overlayStatus" > 
                    <apex:param name="accId" value="{!acc.Id}" assignTo="{!selectedAccId}" />
                </apex:commandlink>
            </apex:column>                    
        </apex:pageBlockTable>                   
</apex:pageBlock><table style="width:100%;">
    <tr>
        <td>
            <apex:commandButton styleClass="btn btn-save pull-right" style="margin-left:10px;" action="{!save}" status="overlayStatus" rerender="outputForm" value="Save"/>
        </td>
    </tr>
</table>
</apex:form>

Controller class:

public class addAccountModalController{public Account objAccount {get;set;}
public Id selectedAccId {get;set;}
private list <Account> allAccounts;
public addAccountModalController(){
    initialize();
}public PageReference addAccount() {
try {
    insert objAccount;
    initialize();
} catch(System.Exception e) {
    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating Account.'));
}
return null;}
public void setAccountsList(List<Account> lstAccount)
{
    this.allAccounts = lstAccount;
}

public List<Account> getAccountsList()
{
    return allAccounts = [SELECT id,Name,Primary_Email__c,createdDate FROM Account ORDER by createdDate DESC LIMIT 5];  
}
 private void initialize()
{
    objAccount = new account(
    //recordType.id = '01290000001GbSj', 
    //recordType.Name = 'Entity'
    );
    objAccount.Name = '';
    objAccount.Primary_Email__c = '';
    getAccountsList();
}


public PageReference save() {
try {       
    update allAccounts;
    getAccountsList();
} catch(System.Exception e) {
    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
}
return null;}
public pageReference delAccount() {
try {
    delete new Account(Id = selectedAccId);
    getAccountsList();
} catch(System.Exception e) {
    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error creating record.'));
}
return null;}} 

I have added initialized() method and let me know if is working.

Thanks, Santanu

3
  • Thanks Santanu, however the class is not saving due to "Method does not exist or incorrect signature: initialize()" Commented Jun 9, 2016 at 7:07
  • which method it is talking about. May be due to some formatting here, that could be missed. I have run the functionality at my developer edition and it is working fine. I have given 2 hours effort to make it workable Commented Jun 9, 2016 at 17:22
  • private void initialize() { objAccount = new account( //recordType.id = '01290000001GbSj', //recordType.Name = 'Entity' ); objAccount.Name = ''; objAccount.Primary_Email__c = ''; getAccountsList(); } Commented Jun 9, 2016 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .