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());
}
}
}
}