I want to use a pageBlockTable to display a grid of customers and their products, with each cell of the grid showing the quantity bought.
As the number of products may change, the grid needs to be dynamic. The only way that I've found to display and save the data for each row is to create a subclass acting as a data structure to display the customer name for each row along with a List to hold the products for that row.
Unfortunately, when I use this subclass the headers don't display. I have created a couple of examples pages which get their data from the same controller.
public with sharing class TestController {
// Data for the first example
public List<Account> accounts {get; set;}
public List<Product2> products {get; set;}
// Data for the second example
public List<GridRow> gridRows {get; set;}
public TestController() {
accounts = new List<Account>();
accounts.add(new Account(Name='One'));
accounts.add(new Account(Name='Two'));
accounts.add(new Account(Name='Three'));
products = new List<Product2>();
products.add(new Product2(Name='Product One'));
products.add(new Product2(Name='Product Two'));
products.add(new Product2(Name='Product Three'));
gridRows = new List<GridRow>();
for(Integer cust = 0; cust < 3; cust++) {
GridRow row = new GridRow();
row.acc = new Account(Name='Customer '+cust);
List<Product2> prods = new List<Product2>();
for(Integer p = 0; p < 3; p++) {
prods.add(new Product2(Name='Product '+p));
}
row.products = prods;
gridRows.add(row);
}
}
public class GridRow {
public Account acc {get; set;}
public List<Product2> products = new List<Product2>();
public List<Product2> getProducts() {
return products;
}
}
}
The first page uses lists that are members of the controller. The headers display fine for this page.
<apex:page controller="TestController">
<apex:pageBlock >
<apex:pageBlockTable value="{!accounts}" var="a">
<apex:column headerValue="Customer">
<apex:outputField value="{!a.Name}" />
</apex:column>
<apex:repeat value="{!products}" var="p">
<apex:column headerValue="{!p.Name}">
<input type="text" />
</apex:column>
</apex:repeat>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
The second uses a list of the subclass object to display the rows of data. The headers won't display for this page.
<apex:pageBlock >
<apex:pageBlockTable value="{!gridRows}" var="row">
<apex:column headerValue="Customer">
<apex:outputField value="{!row.acc.Name}" />
</apex:column>
<apex:repeat value="{!row.products}" var="p">
<apex:column headerValue="{!p.Name}">
<input type="text" />
</apex:column>
</apex:repeat>
</apex:pageBlockTable>
</apex:pageBlock>
I have read this salesforce stackexchange post, but I'm not sure why it says that:
If you are using a List, there is an important gotcha with dynamic tables: header cells are not rendered.
What is the difference between using the List of Accounts and List of Product2s in the first working example and using the List of subclass instances with their Product2 Lists in the second example?