Newer Version Available
Creating and Displaying Dynamic Components
There are two parts to embedding dynamic Visualforce components on your page:
- Adding an <apex:dynamicComponent> tag somewhere on your page. This tag acts as a placeholder for your dynamic component.
- Developing a dynamic Visualforce component in your controller or controller extension.
The <apex:dynamicComponent> tag has one
required attribute—componentValue—that accepts the name of an Apex method that returns a
dynamic component. For example, if you wanted to dynamically generate the title of a
section header differently if the deadline for a submitting form has passed, you could
use the following markup and controller
code:
You
can have multiple <apex:dynamicComponent>
components on a single page.
1<apex:page standardController="Contact" extensions="DynamicComponentExample">
2 <apex:dynamicComponent componentValue="{!headerWithDueDateCheck}"/>
3 <apex:form>
4 <apex:inputField value="{!Contact.LastName}"/>
5 <apex:commandButton value="Save" action="{!save}"/>
6 </apex:form>
7</apex:page>1public class DynamicComponentExample {
2 public DynamicComponentExample(ApexPages.StandardController con) { }
3 public Component.Apex.SectionHeader getHeaderWithDueDateCheck() {
4 date dueDate = date.newInstance(2011, 7, 4);
5 boolean overdue = date.today().daysBetween(dueDate) < 0;
6
7 Component.Apex.SectionHeader sectionHeader = new Component.Apex.SectionHeader();
8 if (overdue) {
9 sectionHeader.title = 'This Form Was Due On ' + dueDate.format() + '!';
10 return sectionHeader;
11 } else {
12 sectionHeader.title = 'Form Submission';
13 return sectionHeader;
14 }
15 }
16}Each dynamic component has access to a common set of methods and properties. You can review this list in the Apex Developer's Guide in the chapter titled “Component Class”.
Dynamic Custom Components
Using custom components dynamically works exactly the same as the standard Visualforce components. Just
change the namespace to that of the custom component. Your custom components are in
the c namespace, so you can create one
dynamically like
this:
1Component.c.MyCustomComponent myDy = new Component.c.MyCustomComponent();As a convenience for your own components, you can omit the namespace, like
so:
1Component.MyCustomComponent myDy = new Component.MyCustomComponent();If you are using components provided by a third party in a package, use the namespace
of the package
provider:
1Component.TheirName.UsefulComponent usefulC = new Component.TheirName.UsefulComponent();Passing Attributes through the Constructor
Instead of setting component attributes via their properties, you can simply pass in
a list of one or more attributes through the
constructor:
If
an attribute isn’t defined in the constructor, the component's default values
are used for that attribute.
1Component.Apex.DataList dynDataList =
2 new Component.Apex.DataList(id='myDataList', rendered=true);There are two components that must have an attribute defined in the constructor,
rather than through a property:
- Component.Apex.Detail must have showChatter=true passed to its constructor if you want to display the Chatter information and controls for a record. Otherwise, this attribute is always false.
- Component.Apex.SelectList must have multiSelect=true passed to its constructor if you want the user to be able to select more than one option at a time. Otherwise, this value is always false.
Defining Expressions and Arbitrary HTML
You can add expression language statements with the expressions property. Append expressions before a property name to pass in an expression statement.
As in static markup, expressions must be wrapped with the {! } syntax. Here’s an
example:
1Component.Apex.Detail detail = new Component.Apex.Detail();
2detail.expressions.subject = '{!Account.ownerId}';
3detail.relatedList = false;
4detail.title = false;Valid expressions include those that refer to fields on standard and custom objects.
Global variables and functions are also available, as demonstrated in this
example:
1Component.Apex.OutputText head1 = new Component.Apex.OutputText();
2head1.expressions.value =
3 '{!IF(CONTAINS($User.FirstName, "John"), "Hello John", "Hey, you!")}';Passing in values through expressions is valid only for attributes that support them. Using {! } outside of the expressions property will be interpreted literally, not as an expression.
If you want to include plain HTML, you can do so by setting the escape property on Component.Apex.OutputText to false:
1Component.Apex.OutputText head1 = new Component.Apex.OutputText();
2head1.escape = false;
3head1.value = '<h1>This header contains HTML</h1>';Defining Facets
Similar to the way expressions are defined, facets act as a special property
available to dynamic components. Here’s an
example:
1Component.Apex.DataTable myTable = new Component.Apex.DataTable(var='item');
2myTable.expressions.value = '{!items}';
3Component.Apex.OutputText header =
4 new Component.Apex.OutputText(value='This is My Header');
5myTable.facets.header = header;For more information on facets, see Best Practices for Using Component Facets.
Defining Child Nodes
You can add child nodes to a dynamic Visualforce component using the childComponents property. The childComponents property acts as a reference to a List of Component.Apex objects.
Here’s an example of how you can use childComponents to construct a <apex:form> with child input
nodes:
1public Component.Apex.PageBlock getDynamicForm() {
2 Component.Apex.PageBlock dynPageBlock = new Component.Apex.PageBlock();
3
4 // Create an input field for Account Name
5 Component.Apex.InputField theNameField = new Component.Apex.InputField();
6 theNameField.expressions.value = '{!Account.Name}';
7 theNameField.id = 'theName';
8 Component.Apex.OutputLabel theNameLabel = new Component.Apex.OutputLabel();
9 theNameLabel.value = 'Rename Account?';
10 theNameLabel.for = 'theName';
11
12 // Create an input field for Account Number
13 Component.Apex.InputField theAccountNumberField = new Component.Apex.InputField();
14 theAccountNumberField.expressions.value = '{!Account.AccountNumber}';
15 theAccountNumberField.id = 'theAccountNumber';
16 Component.Apex.OutputLabel theAccountNumberLabel = new Component.Apex.OutputLabel();
17 theAccountNumberLabel.value = 'Change Account #?';
18 theAccountNumberLabel.for = 'theAccountNumber';
19
20 // Create a button to submit the form
21 Component.Apex.CommandButton saveButton = new Component.Apex.CommandButton();
22 saveButton.value = 'Save';
23 saveButton.expressions.action = '{!Save}';
24
25 // Assemble the form components
26 dynPageBlock.childComponents.add(theNameLabel);
27 dynPageBlock.childComponents.add(theNameField);
28 dynPageBlock.childComponents.add(theAccountNumberLabel);
29 dynPageBlock.childComponents.add(theAccountNumberField);
30 dynPageBlock.childComponents.add(saveButton);
31
32 return dynPageBlock;
33}If your markup is defined as:
Then
your markup is equivalent to the following static
markup:
Notice
that the order of elements in the equivalent static markup is the order in which the
dynamic components were added to childComponents, not the order in which they were declared in the Apex
code of the getDynamicForm method.
1<apex:form>
2 <apex:dynamicComponent componentValue="{!dynamicForm}"/>
3</apex:form>1<apex:form>
2 <apex:pageBlock>
3 <apex:outputLabel for="theName"/>
4 <apex:inputField value="{!Account.Name}" id="theName"/>
5 <apex:outputLabel for="theAccountNumber"/>
6 <apex:inputField value="{!Account.AccountNumber}" id="theAccountNumber"/>
7 <apex:commandButton value="Save" action="{!save}"/>
8 </apex:pageBlock>
9</apex:form>