I am trying to display Grandchild records however I am not getting the page layout correctly.

I am using page-blocks to display the data however from the picture below the columns of the child object is not displaying correctly. It is off center. I will be displaying more columns but conceptually as you can see my page is off.

[1]: https://i.stack.imgur.com/KfMzI.png

<apex:page standardController="SBQQ__Quote__c" extensions="G_SPRFormExtension" >
<apex:pageBlock >
        <apex:pageblocksection columns="2">

            <apex:outputField value="{!SBQQ__Quote__c.name}"/>
            <apex:outputField value="{!SBQQ__Quote__c.SBQQ__Status__c}"/> 


  <apex:pageBlock >

      <apex:pageblocktable value="{!lstHost}" var="host">

        <apex:column headerValue="Host">
              <apex:outputfield value="{!host.Name}"/>


            <apex:column headerValue="Host">

              <apex:outputfield value="{!host.Pole_Piece__c}"/>

    <apex:column breakBefore="true"> 

      <apex:pageBlock title="{!host.name} to Asset">
          <apex:pageblocktable value="{!host.Assets__r}" var="asset">

              <apex:column headerValue="Asset">
                  <apex:outputfield value="{!asset.Name}"/>

              <apex:column headerValue="Model #">
                  <apex:outputfield value="{!asset.Model__c}"/>

              <apex:column headerValue="COT Number">
                  <apex:outputfield value="{!asset.Roper_Order__c}"/>

              <apex:column headerValue="Serial Number">
                  <apex:outputfield value="{!asset.SerialNumber}"/>




public class G_SPRFormExtension {

Private SBQQ__Quote__c soQuote {get;set;}

public  List<Host__c> lstHost {get;set;}

public List<Asset> lstHost_Assets {get;set;}
Private Set<Id> idHostAsset = new Set<Id>();
//public List<Contact> cont{get;set;}

 Public String getAccountID() {
    return soQuote.SBQQ__Account__c;

Public G_SPRFormExtension(ApexPages.StandardController stdController) 
     system.debug(logginglevel.debug, 'DEBUG: START CONSTRUCTOR');

    // Get Case ID number 
    This.soQuote = (SBQQ__Quote__c)stdController.getRecord(); 

    //Get the Case Values for this record
    soQuote = [Select Id, Name, SBQQ__Status__c, SBQQ__Account__c
               From SBQQ__Quote__c 
                Where Id = :This.soQuote.Id]; 

     system.debug(logginglevel.debug, 'DEBUG: soQuote' + soQuote );



Public Void GetHosts()

    lstHost = [Select Id, Name, Model__c, Pole_Piece__c, ( Select Name, Model__c, Roper_Order__c, SerialNumber from Assets__r)
                 From Host__c 
                    Where Location__c  = :soQuote.SBQQ__Account__c];

  • 1
    What do you mean by off center? What's the objective? Have you tried using an <apex:repeat> rather than nesting a page block inside a table (surprised that works, actually). – David Reed Jul 2 '18 at 14:10
  • Its not "off-center", its nested inside of a column, which is exactly the way you wrote it. I dont think you'll be able to use css to modify the boundary of the table columns to extend your pageBlock, I think you'll need to approach this problem differently. – battery.cord Jul 2 '18 at 14:12
  • Sorry added the picture late. I wanted my column of host to be right next to each other. – Brooke Jul 2 '18 at 14:16
  • I tried using the Repeat however I found that it is not nicely formatted as the page block. The repeat gives me the data value squished next to each other. So its kind of the same problem i.e repeater squishes the data next to each other the page block separates the data far apart. – Brooke Jul 2 '18 at 14:18
  • If you really want a table, inside a table, try setting the colspan attribute of the wrapping column to however many columns you have. You'll probably need an empty row to fit the data into, which doesn't really mesh with the column based table generation salesforce uses. I'm working on an example using wrapper classes on how to show related data. – battery.cord Jul 2 '18 at 14:31

For grandchild records, I usually use a wrapper class instead of trying to create extra tables. Trying to fit extra tables into the salesforce table layout usually goes pretty poorly, they just weren't designed for it. You could try to write your own table, but then you have to do styling, and formatting, and it turns into a time-sink, really.

A wrapper class is an apex class which is used to store one or more sObject references. This is the data the class represents, and since its a data type, we can use our wrapper class instead of direct, from the database records. (A search for "wrapper class" on here or google should give some good extra reading on the subject).

The best way we can format our data is to have it fit the column based design of apex tables. We do this by taking our child data, and storing it in a wrapper class with some parent data. We can then iterate over this data together, instead of one or the other, to show a related list with information from both tables. I'd still display the first set of child records in a separate list, then right under it, a list of wrappers with information about the grandchildren.

Heres our wrapper class. It stores two records, one of our children (parent), and one of the child's child (child). We can use the type WrapperClass instead of an sObject to iterate over.

public class WrapperClass {

    public sObject child { get; set; } // grand-child 
    public sObject parent { get; set; } // child

    public Wrapper(sObject child, sObject parent) {
        this.child = child; 
        this.parent = parent; 

Heres how we can use it in a table. These records fit into their own table, and have one row per grand-child. You can use child and grand-child fields, since both objects are included in the class.

<apex:pageblocktable value="{!records}" var="record">

    <apex:column headerValue="Record Name">
        <apex:outputfield value="{!host.child.Name}"/>

    <apex:column headerValue="Parent Name">
        <apex:outputfield value="{!host.parent.Name}"/>


Finally, our class that creates the data.

// Variable to store wrappers 
public List<WrapperClass> records { get; set; }

// Method to get data based on an id 
public void GetData(Id parentId) {
    records = new List<WrapperClass>(); // reset variable 

    // Query our children, grandchilren from the parent 
    List<sObject> children = [SELECT Id, Name, (SELECT Name, Id FROM ChildRelationship) FROM Contact WHERE AccountId = :ParentId];

    // Loop over records & create a unique row per grandchild 
    for (sObject child:children) {
        for (sObject grandchild:child.ChildRelationship) {
            records.add(new WrapperClass(grandchild, child));

This ends up looking like a normal table. For tables-in-tables, you'll need to do some custom table work using the bare html table tag.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.