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
JimmyMacJimmyMac 

How To Display A Related List Of Custom Objects / And How To Pass A Variable Into Apex Method

I have 2 custom objects related by a related list definition (called Holdings):

1. financial_acct__c

2.Holding__c

 

I need to display in the follwoing format in a VisualForce Page: (The tables are related by AccountId)

 

financial acct: XXX

      Holding1

      Holding2

 

financial acct: YYY

      Holding3

      Holding4

 

Once way I tried was to pass the finacial account id into a method getRelated() which would bring back a list of the related holdings. But when I tried to pass the

Account Id by using a <apex param> it was null when I debugged it in the method. I had declared the param variable as Public String myKey(get{}:,set{}}

 

When I debugged it in the class, it said myKey was null. When you do the "assignto=myKey"  in the <apex:param tag, doesn't that put the value in the variable?

 

 

 

 

 

Can you please help me out, I have been trying everything!

 

Best Answer chosen by Admin (Salesforce Developers) 
kriskkrisk

So here is your solution

 

VF Page:

 

<apex:page controller="ContactSearchController">
<apex:repeat value="{!accountMap}" var="key">
<apex:outputText value="{!key}" />
<ul>
<apex:repeat value="{!accountMap[key]}" var="map">
<Apex:outputText value="{!map}"/> <br/>
</apex:repeat>
</ul>
</apex:repeat>
</apex:page>

 

Controller:

 

public class ContactSearchController {

private Map<String,Set<String>> accountMap = new Map<String,Set<String>>();

public ContactSearchController(){

List<Financial_Account__c> financialAccountList = [Select f.Name, f.Id From Financial_Account__c f];

for(Financial_Account__c account:financialAccountList){
string accountId = account.Id;
Set<String> holdingCompanies = new Set<String>();
List<Holding__c> holdingList = [Select h.Name From Holding__c h where h.Account_Id__c=:accountId];
for(Holding__c h:holdingList){
holdingCompanies.add(h.Name);
}
accountMap.put(account.Name, holdingCompanies);
}
}

public Map<String, Set<String>> getAccountMap(){
return accountMap;
}
}

 

All Answers

kriskkrisk

Each of your salesforce objects has a standard controller associated with it. So you can take advantage of the standard controller to display a Financial Account along with a list of related Holdings

 

Say if your Custom Object name is Financial_Account__c and the Child Object is Holding__c. Also look at how you named the Plural reference for your Child object while creating the object. Most likely you must have called it Holdings and so you will refer to the lists as Holdings__r

 

Create a Visual Force custom page with the following mark up

 

<apex:page standardController="Financial_Account__c">
<apex:pageBlock >
<apex:relatedList list="Holdings__r" title="{!Financial_Account__c.name} Holdings"/>
</apex:PageBlock>
</apex:page>

 

Say your page name is relatedHoldings. So invoke the page by providing the Id for Financial Account object like below example

 

https://c.na8.visual.force.com/apex/relatedHoldings?id=a0KC0000009t5jV

JimmyMacJimmyMac

Thanks but what I am doing is just a small section of a page, it isn't the ONLY thing on the page so I have a custom controller(ContactSearchController) defined to do other things.

So should I use the standard controller for financial_account_c and then use the extensions attribute to extend the class?

 

Like so:

<apex:page controller="financial_account_c" extensions="ContactSearchController" sidebar="false" renderAs="{!chooserender}" >

 

if I do this then can I do what you suggested?

 

Thanks so much.

-Jim

kriskkrisk

Read the page parameter Id and look up holdingList. 

 

In the page you are going to reference the list as holdingList 

 

public class ContactSearchController {

private List<Holding__c> holdingList {get; set;}

public ContactSearchController()
{
string accountId = ApexPages.currentPage().getParameters().get('id');
holdingList = [Select h.Name, h.Id From Holding__c h where h.Account_Id__c=:accountId];
}
}

JimmyMacJimmyMac

Thanks so much for your help here I truly appreciate your time!

 

I know how to do that if the user does some type of action like "click a link" or "click a button"... I then associate the action to a Apex method.

In fact my temp solution right now is just that, when the user clicks the Account link I do exactly what you show me to do, it goes out and gets the related info and then

I display it.

 

But my goal is to have it all displayed as a parent/child related list.without having the user do any action.

 

So how in the Visualforce Page do I loop, and call the Apex method with the AccountId  to load the child data? From what I have read it doesn't look like there is anyway to call the Apex method from within the page unless it is fired by some user action.

 

Ive been working on this straight for 3 long days and would love to find a solution, Thnks again!

kriskkrisk

There is a limitation for using Maps in VF - I believe it is a big limitation. So for now I was able to concatenate the Holding companies to display on  VF page. Here is the code for Controller and VF Page.

 

Controller:

 

public class ContactSearchController {

private Map<String, String> accountMap = new Map<String, String>();

public ContactSearchController(){

List<Financial_Account__c> financialAccountList = [Select f.Name, f.Id From Financial_Account__c f];

for(Financial_Account__c account:financialAccountList){
string accountId = account.Id;
string holdingCompanies = '';
List<Holding__c> holdingList = [Select h.Name From Holding__c h where h.Account_Id__c=:accountId];
for(Holding__c h:holdingList){
holdingCompanies = holdingCompanies + h.Name + '; ';
}
accountMap.put(account.Name, holdingCompanies);
}
}

public Map<String, String> getAccountMap(){
return accountMap;
}
}

 

VF Page:

 

<apex:page controller="ContactSearchController">
<apex:pageblock title="Map Usage On VF">
<apex:pageBlockTable value="{!accountMap}" var="d">
<apex:column headerValue="Account Name">
{!d}
</apex:column>
<apex:column headerValue="Holding Companies">
{!accountMap[d]}
</apex:column>
</apex:pageBlockTable>
</apex:pageblock>
</apex:page>

JimmyMacJimmyMac

Nice idea... I like the concept but I think you gave me a better idea....

 

What about doing a MAP of a Financial Account and a SET of values (Data for the related Holding)

 

So we would have:

 

Financiial Account: FA-013

SET = Hld1,123,456,abc

 

Financiial Account: FA-014

SET = Hld1,123,456,abc

SET = Hld1,321,333,zzz

 

The MAP would use the Finacial Account as the KEY and the SET as it's values

 

MAP(FA-013,Hld1,123,456,abc)

MAP(FA-014,Hld1,123,456,abc)

MAP(FA-014,Hld1,321,333,zzz)

 

Then couldn't we in the page, Loop thru the MAP , and do a <repeat loop for the Holdings info?... What do you think?....Thanks so much for all your effort!

 

 

 

 

 

kriskkrisk

So here is your solution

 

VF Page:

 

<apex:page controller="ContactSearchController">
<apex:repeat value="{!accountMap}" var="key">
<apex:outputText value="{!key}" />
<ul>
<apex:repeat value="{!accountMap[key]}" var="map">
<Apex:outputText value="{!map}"/> <br/>
</apex:repeat>
</ul>
</apex:repeat>
</apex:page>

 

Controller:

 

public class ContactSearchController {

private Map<String,Set<String>> accountMap = new Map<String,Set<String>>();

public ContactSearchController(){

List<Financial_Account__c> financialAccountList = [Select f.Name, f.Id From Financial_Account__c f];

for(Financial_Account__c account:financialAccountList){
string accountId = account.Id;
Set<String> holdingCompanies = new Set<String>();
List<Holding__c> holdingList = [Select h.Name From Holding__c h where h.Account_Id__c=:accountId];
for(Holding__c h:holdingList){
holdingCompanies.add(h.Name);
}
accountMap.put(account.Name, holdingCompanies);
}
}

public Map<String, Set<String>> getAccountMap(){
return accountMap;
}
}

 

This was selected as the best answer
JimmyMacJimmyMac

Fantastic, you have taught a "newbie" a great deal from all this, thank you so much for your help.

-Jim

kriskkrisk

I am happy that you are happy. 

 

I extended your solution a bit more to include one more level of Nesting. So this has 3 levels

 

Financial Account

     Holding Company

         Sub Holding Company

 

Here is the code.

 

Controller

 

public class ContactSearchController {

private Map<String,Set<String>> accountMap = new Map<String,Set<String>>();
private Map<String,Set<String>> holdingMap = new Map<String,Set<String>>();

public ContactSearchController(){

List<Financial_Account__c> financialAccountList = [Select f.Name, f.Id From Financial_Account__c f];

for(Financial_Account__c account:financialAccountList){
string accountId = account.Id;
Set<String> holdingCompanies = new Set<String>();
List<Holding__c> holdingList = [Select h.Id,h.Name From Holding__c h where h.Account_Id__c=:accountId];
for(Holding__c h:holdingList){
string holdingId = h.Id;
holdingCompanies.add(h.Name);
List<Sub_Holding__c> subHoldingList = [Select sh.Id,sh.Name From Sub_Holding__c sh where sh.Holding__c=:holdingId];
Set<String> subHoldingCompanies = new Set<String>();
for(Sub_Holding__c sh:subHoldingList){
subHoldingCompanies.add(sh.Name);
}
holdingMap.put(h.Name, subHoldingCompanies);
}
accountMap.put(account.Name, holdingCompanies);
}
}

public Map<String, Set<String>> getAccountMap(){
return accountMap;
}

public Map<String, Set<String>> getHoldingMap(){
return holdingMap;
}
}

 

VF Page Markup:

 

<apex:page controller="ContactSearchController">
<apex:repeat value="{!accountMap}" var="key">
<apex:outputText value="{!key}" />
<ul>
<apex:repeat value="{!accountMap[key]}" var="map">
<Apex:outputText value="{!map}"/> <br/>
<ul>
<apex:repeat value="{!holdingMap[map]}" var="submap">
<Apex:outputText value="{!submap}"/> <br/>
</apex:repeat>
</ul>
</apex:repeat>
</ul>
</apex:repeat>
</apex:page>