Menu Bar

Wednesday, 26 June 2013

Retrieve Related Object Fields

Retrieve Related Object Fields

[Say we wanna display all the related fields of a record, using Vlookup of single field of a record, Here that goes.....]
A short post this week, again based on a question from the DeveloperForce Visualforce Discussion Board regarding the retrieval of a related objects fields.  In this particular case, an sobject is being created/edited via Visualforce and once a lookup field is populated, the developer wanted to display some fields related to the lookup.

Unsurprisingly, simply adding some outputfields for the  related object as shown below doesn't do the trick:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<apex:page standardcontroller="Contact">
 <apex:form >
   <apex:pageBlock title="Contact Create/Edit">
      <apex:pageBlockSection title="Contact Information">
       <apex:inputField value="{!contact.FirstName}"/>
       <apex:inputField value="{!contact.LastName}"/>
      </apex:pageBlockSection>
      <apex:pageBlockSection title="Account Information">
       <apex:inputField value="{!contact.AccountId}"/>
       <apex:outputField value="{!contact.Account.AccountNumber}"/>
       <apex:outputField value="{!contact.Account.Site}"/>
      </apex:pageBlockSection>
   </apex:pageBlock>
  </apex:form>
</apex:page>

Once the lookup is selected, the outputfield values remain empty, as all that has been specified is the id of the account via the inputfield - the related object details aren't populated in the sobject graph, so attempting to traverse the account relationship doesn't bring back any data:



One way to get the information back would be to save the contact once the lookup is populated and carry out a client side redirect to the current page with the id of the newly created contact.  When the standard controller retrieves the new sobject, it will populate the related Account information automatically.  This isn't a great user experience though, as the save is likely to be well before the user is ready, and doesn't give them a chance to change their mind part way through.  Likely to lead to a lot of unwanted and half-populated contacts.

Therefore it looks like an extension controller is the route to go. The page has been updated with an actionsupport component that is attached to the account lookup. This invokes an action method on the extension controller which executes a SOQL query to populate the related account information.

Revised Page:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<apex:page standardcontroller="Contact" extensions="RelatedController">
 <apex:form >
   <apex:pageMessages id="msgs"/>
   <apex:pageBlock title="Contact Create/Edit">
      <apex:pageBlockSection title="Contact Information">
       <apex:inputField value="{!contact.FirstName}"/>
       <apex:inputField value="{!contact.LastName}"/>
      </apex:pageBlockSection>
       <apex:actionRegion >
          <apex:pageBlockSection id="accinfo" title="Account Information">
         <apex:inputField value="{!contact.AccountId}">
            <apex:actionSupport event="onchange" action="{!AccountPopulated}" rerender="accinfo, msgs"/>
         </apex:inputField>
         <apex:outputField value="{!contact.Account.AccountNumber}"/>
         <apex:outputField value="{!contact.Account.Site}"/>
        </apex:pageBlockSection>
      </apex:actionRegion>
      <apex:pageBlockButtons >
        <apex:commandButton value="Cancel" action="{!cancel}"/>
        <apex:commandButton value="Save" action="{!save}"/>
      </apex:pageBlockButtons>
   </apex:pageBlock>
  </apex:form>
</apex:page>

Extension controller: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public with sharing class RelatedController
{
 private ApexPages.StandardController stdCtrl;
  
 public RelatedController(ApexPages.StandardController std)
 {
  stdCtrl=std;
 }
  
 public void AccountPopulated()
 {
  Contact cont=(Contact) stdCtrl.getRecord();
  cont.Account=[select AccountNumber, Site from Account where id=:cont.AccountId];
 }
}
Choosing the account now carries out an Ajax request and rerenders the account information with the fields populated.


Also, as I've been able to write the information into the object relationship, its the same markup that renders the account information regardless of whether it was retrieved via my extension controller or via the standard controller "reflection" when the page is opened with a specified contact id.

Finally, a word of advice - if you are writing an extension controller for this purpose, make sure that the related object has some data present in the fields, otherwise you'll be convinced your code is failing when in fact its working perfectly, just rendering empty fields!

No comments: