Dynamic number of columns in a pageBlockTable

I would like to be able to dynamically control the columns displayed in a page block table. This would mean that if new fields are added to the object the controller and page do not have to be updated.

I understand that a standard list view could used, be the data model is:

Parent_c -< Child_c -< Grandchild__c

And I will be building a page displaying all the grandchildren for a selected Parent, and creating a list view for each parent is not ideal.

Answer

Page Block Tables actually support <apex:repeat> tags (This was not originally supported). The following example demonstrates 2 ways of accomplishing dynamic columns in a table depending on the type of data you supply.

Using fieldsets is the simplest way to control dynamic columns. This is the best choice if displaying a table of SObjects

<apex:pageBlock id="block">
    <apex:pageBlockTable id="table" var="account" value="{!accounts}">
        <apex:column headerValue="Account Name" value="{!account.Name}" />
        <apex:repeat var="f" value="{!$ObjectType.Account.FieldSets.Example_Fieldset}">
            <apex:column headerValue="{!f.label}">
                <apex:inputField value="{!account[f]}" />
            </apex:column>
        </apex:repeat>
    </apex:pageBlockTable>
</apex:pageBlock>

If you are using a List, there is an important gotcha with dynamic tables: header cells are not rendered.
The fix is to declare the following css snippet and apply the style as outlined below

<style type="text/css">
    .empty-column-content {
        display: none;
    }
</style>

<apex:pageBlock id="block2">
    <apex:pageBlockTable id="table" var="row" value="{!rows}">
        <apex:repeat var="cell" value="{!row.cells}">
            <apex:column headerValue="No matter how this is defined, it results in an empty cell">
                <apex:outputText value="{!cell}" />
            </apex:column>
        </apex:repeat>
        <!--Define the headers here and hide the empty cells that are created -->
        <apex:repeat var="header" value="{!headers}">
            <apex:column headerValue="{!header}" styleClass="empty-column-content" />
        </apex:repeat>
    </apex:pageBlockTable>
</apex:pageBlock>

The example controller for the visualforce snippets above:

public with sharing class PageBlockTableFieldSetExample {
    public List<Account> accounts { get; private set; }
    public List<String> headers { get; private set; }
    public List<RowExample> rows { get; private set; }

    public PageBlockTableFieldSetExample() {
        String queryFields = '';
        for(Schema.FieldSetMember f : SObjectType.Account.FieldSets.Example_Fieldset.getFields()) {
            if(queryFields.length() > 0) {
                queryFields += ', ';
            }
            queryFields += f.getFieldPath();
        }
        //Query the records you want to display
        this.accounts = Database.query(
            ' SELECT ' +
                queryFields +
            ' FROM ' +
                ' Account ' +
            ' WHERE ' +
                ' AccountNumber = null ' +
            ' LIMIT 10 ');


        //Setup the row of classes example
        this.headers = new List<String> { 'Monday', 'Tuesday', 'Wednesday' };
        this.rows = new List<RowExample>();
        for(Integer i = 0; i < 3; i++) {
            this.rows.add(new RowExample(this.headers.size()));
        }
    }

    public class RowExample {
        //A variable number of cells in different rows will result in 
        public final List<String> cells { get; private set; }

        public RowExample(Integer length) {
            this.cells = new List<String>();
            for(Integer i = 0; i < 3; i++) {
                this.cells.add('Cell ' + (math.random() * 10).intValue());
            }
        }
    }
}

Attribution
Source : Link , Question Author : Daniel Blackhall , Answer Author : Daniel Blackhall

Leave a Comment