Find your content:

Search form

You are here

Dynamic number of columns in a pageBlockTable

 
Share

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.


Attribution to: Daniel Blackhall

Possible Suggestion/Solution #1

You could using Dynamic Visualforce Components to construct the pageBlockTable, which avoids the limitation re headings when adding columns dynamically in VF alone.

Controller:

public List<Account> getAccountList()
{
    String fieldList = '';
    for(Schema.FieldSetMember fsm : SObjectType.Account.FieldSets.MyFieldset.getFields())
        fieldList += fieldList.length()>0 ? ','+fsm.getFieldPath() : fsm.getFieldPath();
    return (List<Account>) Database.query('select ' + fieldList + ' from Account');
}

public Component.Apex.PageBlockTable getMyPageBlockTable()
{
    Component.Apex.PageBlockTable table = new Component.Apex.PageBlockTable(var='acc');
    table.expressions.value='{!AccountList}';
    for(Schema.FieldSetMember fsm : SObjectType.Account.FieldSets.MyFieldset.getFields())
    {
        Component.Apex.OutputField outputField = new Component.Apex.OutputField();
        outputField.expressions.value = '{!acc.' + fsm.getFieldPath() + '}';
        Component.Apex.Column column = new Component.Apex.Column(headerValue=fsm.getLabel());
        column.childComponents.add(outputField);
        table.childComponents.add(column);
    }
    return table;
}

Visualforce page:

<apex:pageBlock >
    <apex:dynamicComponent componentValue="{!MyPageBlockTable}"/>
</apex:pageBlock>

Attribution to: Stephen Willcock

Possible Suggestion/Solution #2

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 to: Daniel Blackhall
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/245

My Block Status

My Block Content