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
Eric FortenberryEric Fortenberry 

How should I modify this Visuaulforce code to show all Contacts from all child Accounts?

I am trying to create a visualforce page that I will use to replace the standard contact related list on the Account page layout.  I want this new visualforce page to show all contacts associated with the current account, as well as from all the child accounts.  What is the best way to modify this code to display all the contacts?

 

<apex:page standardController="Account" sidebar="false" showHeader="false">
<apex:pageBlock title="All Related Account Contacts">
<apex:pageBlockTable value="{! account.contacts}" var="item">
<apex:column value="{! item.name}"/>
<apex:column value="{! item.account.name}"/>
<apex:column value="{! item.phone}"/>
<apex:column value="{! item.email}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

Best Answer chosen by Admin (Salesforce Developers) 
Paul.FoxPaul.Fox

You'll need to setup a custom controller for the Apex Page since this is not a part of the standard controller

 

in apex:page you'll need to add Extensions="AccountExt" or something like that.

 

You'll need to lookup in the docs how to extend a standard controller and use all the right methods in the extension.

 

Then you'll need a new method like this in the AccountExt class:

 

public list<Contact> getAllContacts(){
set<Id> AccountIds = new set<Id>();
AccountIds.add(acc.Id); // acc should be defined as part of the standard controller extension logic
 
// This repeats for up to 5 levels of Account Children, could go more if you want
for(integer i=0;i<5;i++){
for(Account a: [select Id from Account where ParentId in :AccountIds])
    AccountIds.add(a.Id);
}
return [select FirstName, LastName, Title, Account.Name, Phone, Email from Contact where AccountId in :AccountIds];

}

 Then just change the apex:pageBlockTable value to {!AllContacts}

All Answers

Paul.FoxPaul.Fox

You'll need to setup a custom controller for the Apex Page since this is not a part of the standard controller

 

in apex:page you'll need to add Extensions="AccountExt" or something like that.

 

You'll need to lookup in the docs how to extend a standard controller and use all the right methods in the extension.

 

Then you'll need a new method like this in the AccountExt class:

 

public list<Contact> getAllContacts(){
set<Id> AccountIds = new set<Id>();
AccountIds.add(acc.Id); // acc should be defined as part of the standard controller extension logic
 
// This repeats for up to 5 levels of Account Children, could go more if you want
for(integer i=0;i<5;i++){
for(Account a: [select Id from Account where ParentId in :AccountIds])
    AccountIds.add(a.Id);
}
return [select FirstName, LastName, Title, Account.Name, Phone, Email from Contact where AccountId in :AccountIds];

}

 Then just change the apex:pageBlockTable value to {!AllContacts}

This was selected as the best answer
Eric FortenberryEric Fortenberry

I have created the AccountExt and updated my visualforce page, however, I am getting the following error:

 

System.NullPointerException: Attempt to de-reference a null object

 

Class.AccountExt.getAllContacts: line 9, column 1     

 

Here is my AccountExt code:

public class AccountExt {

    public AccountExt(ApexPages.StandardController controller) {
    }
    private final Account acc;
    public list<Contact> getAllContacts(){ 
        Set<id> AccountIds = new set<ID>();
        AccountIds.add(acc.Id);
        for(integer i=0;i<5;i++){
            for(Account a: [select Id from Account where ParentId in :AccountIds])
            AccountIds.add(a.Id);
        }
        return [select FirstName, LastName, Title, Account.Name, Phone, Email from Contact where AccountId in :AccountIds];
        }
}

 

 

And my visualforce code:

<apex:page standardController="Account" extensions="AccountExt" sidebar="false" showHeader="false">
    <apex:pageBlock title="All Related Account Contacts">
        <apex:pageBlockTable value="{!AllContacts}" var="item">
            <apex:column value="{! item.name}"/>
            <apex:column value="{! item.account.name}"/>
            <apex:column value="{! item.phone}"/>
            <apex:column value="{! item.email}"/>            
        </apex:pageBlockTable>
    </apex:pageBlock>  
</apex:page>

 

Paul.FoxPaul.Fox

acc is empty, you never assign a value to it.

 

AccountExt should look like this:

public AccountExt(ApexPages.StandardController controller) {
    acc = (Account) controller.getRecord();
    }

 

Eric FortenberryEric Fortenberry

Thank you Paul!  This now works!

 

One more question, is there any way to drop this component in place of the Contacts related List, or can it only be added above in the Details section of the account?

 

And if that's the case, what is the best way to add the New Contact button to my new visualforce page?  Here's what I tried, but am geting the following error:  "Error: apex:commandButton must occur between <apex:form></apex:form> tags"

<apex:page standardController="Account" extensions="AccountExt" sidebar="false" showHeader="false">
    <apex:pageBlock >
        <apex:pageBlockButtons>
            <apex:commandButton action="{!NewContact}" value="New Contact"/>
        </apex:pageBlockButtons>
        <apex:pageBlockTable value="{!AllContacts}" var="item">
            <apex:column value="{! item.name}"/>
            <apex:column value="{! item.account.name}"/>
            <apex:column value="{! item.phone}"/>
            <apex:column value="{! item.email}"/>            
        </apex:pageBlockTable>
    </apex:pageBlock>  
</apex:page>

 

Paul.FoxPaul.Fox

You can either embed this visualforce page inside of the detail section, or you can ovverride the entire account page and then you can put it wherever you want, but you'll need to do a few more things first.

 

Check out the section of this tutorial that discusses overriding the view page. The example is for contacts, but you can see how it would work for Accounts.

 

As for the apex:form error, just make sure that you put <apex:form> and </apex:form> around your pageblock tags.

Eric FortenberryEric Fortenberry

How would I make the item.name a clickable link that opens up the contact detail page?

 

<apex:page standardController="Account" extensions="AccountExt" sidebar="false" showHeader="false">
    <apex:pageBlock >
        <apex:pageBlockTable value="{!AllContacts}" var="item">
            <apex:column value="{! item.name}"/>
            <apex:column value="{! item.account.name}"/>
            <apex:column value="{! item.phone}"/>
            <apex:column value="{! item.email}"/>            
        </apex:pageBlockTable>
    </apex:pageBlock>  
</apex:page>

 I think I need to use URLFOR, but I can't seem to figure it out...  

Eric FortenberryEric Fortenberry

Ok, I figured out the link part; however, when I click the link from the Account page, it tries to render itself within the visualforce page instead of re-rendering the entire page.

 

<apex:page standardController="Account" extensions="AccountExt" sidebar="false" showHeader="false">
    <apex:pageBlock >
        <apex:pageBlockTable value="{!AllContacts}" var="item">
            <apex:column >
                 <apex:outputLink value="/{!item.id}" id="Contact">{!item.name}</apex:outputLink>
            </apex:column>
            <apex:column value="{! item.account.name}"/>
            <apex:column value="{! item.phone}"/>
            <apex:column value="{! item.email}"/>            
        </apex:pageBlockTable>
    </apex:pageBlock>  
</apex:page>

 

Eric FortenberryEric Fortenberry

Ok, nevermind again.  I added the target="_top" parameter and it worked.