[SalesForce] How to create a dynamic list in Visualforce

I want to create a view of certain custom fields and objects, with the data for the view computed in a controller with input from SOQL statements from custom objects.
The view would consist of several dynamic elements and fields, in a view that does not match just one object.

Now I have tried the basics of Visualforce and APEX controllers, but do not understand which way to make a dynamic list in Visualforce. Eg the number of entries in the list is dynamic.
I have read some examples, for instance in the Visualforce workbook, where I could just use a standard control to view of one of my custom objects.

Maybe I could create a specific custom object for displaying the information,
but what I would prefer, is if I have full control in the controller code to compute the values and then display them.

One way to do this looks like the example

    <apex:pageBlockTable value="{! account.contacts}" var="item">
         <apex:column value="{!item.FirstName}"/>
    </apex:pageBlockTable>

But replaced with a list of custom objects instead of account and contacts.
I do not have the ID of the object in the visualforce call, instead this will be based on a inputField from the user, with a set method.

The only real example I have found is How can I create tables Dynamically in a VisualForce
using dynamic components in a list and then push them to the page?

Are there any other alternatives?

Best Answer

This Visualforce table can display a table of arbitrary fields from arbitrary SObjects by making use of map syntax:

<apex:page controller="MyController">
    <apex:pageBlock>
        <apex:pageBlockTable value="{!items}" var="item">
            <apex:repeat value="{!keys}" var="key">
                <apex:column value="{!item[key.sob][key.field]}"/>
            </apex:repeat>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

The corresponding controller - I've just used some random queries for this example - looks like this:

public with sharing class MyController {
    public class Key {
        public String sob {get; set;}
        public String field {get; set;}
        Key(String sob, String field) {
            this.sob = sob;
            this.field = field;
        }
    }
    public List<Map<String, SObject>> items {
        get {
            List<Map<String, SObject>> l = new List<Map<String, SObject>>();
            Account[] accounts = [select Name from Account limit 5];
            Contact[] contacts = [select FirstName, Birthdate from Contact limit 5];
            for (Integer i = 0; i < 5; i++) {
                Map<String, SObject> m = new Map<String, SObject>();
                m.put('Account', accounts[i]);
                m.put('Contact', contacts[i]);
                l.add(m);
            }
            return l;
        }
    }
    public Key[] keys {
        get {
            return new Key[] {
                    new Key('Contact', 'Birthdate'),
                    new Key('Account', 'Name'),
                    new Key('Contact', 'FirstName')
                    };
        }
    }
}

It is the keys array returned that determines the table columns displayed with one attribute choosing the SObject and the other attribute choosing the field in that SObject. By referencing the field directly the column heading and presentation formatting are automatically driven by the field's metadata.

Note that this is not a typical solution. In Salesforce, tables usually only contain fields from one object.

Related Topic