Newer Version Available

This content describes an older version of this product. View Latest

Defining Templates with <apex:composition>

All templates defined using <apex:composition> must have one or more child <apex:insert> tags. An <apex:insert> tag indicates to pages that import the template that a section needs a definition. Any Visualforce page that imports a template using <apex:composition> must use <apex:define> to specify the content of each <apex:insert> section of the template.

You can create a skeleton template that allows subsequent Visualforce pages to implement different content within the same standard structure. To do so, create a template page with the <apex:composition> tag.

The following example shows how you can use <apex:composition>, <apex:insert>, and <apex:define> to implement a skeleton template.

First, create an empty page called myFormComposition that uses a controller called compositionExample:
1<apex:page controller="compositionExample">
2
3</apex:page>
After saving the page, a prompt appears that asks you to create compositionExample. Use the following code to define that custom controller:
1swfobject.registerObject("clippy.codeblock-1", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class compositionExample{
18
19    String name;
20    Integer age;
21    String meal;
22    String color;
23    
24    Boolean showGreeting = false;
25    
26    public PageReference save() {
27        showGreeting = true;
28        return null;
29    }
30    
31    public void setNameField(String nameField) {
32        name = nameField;
33    }
34    
35    public String getNameField() {
36        return name;
37    }
38    
39    public void setAgeField(Integer ageField) {
40        age= ageField;
41    }
42    
43    public Integer getAgeField() {
44        return age;
45    }
46    
47    public void setMealField(String mealField) {
48        meal= mealField;
49    }
50    
51    public String getMealField() {
52        return meal;
53    }   
54         
55    public void setColorField(String colorField) {
56        color = colorField;
57    }
58    
59    public String getColorField() {
60        return color;
61    }       
62    
63    public Boolean getShowGreeting() {
64        return showGreeting;
65    }
66}
Next, return to myFormComposition and create a skeleton template:
1swfobject.registerObject("clippy.codeblock-2", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<apex:page controller="compositionExample">
18    <apex:form >
19        <apex:outputLabel value="Enter your name: " for="nameField"/>
20        <apex:inputText id="nameField" value="{!nameField}"/>
21        <br />
22        <apex:insert name="age" />
23        <br />
24        <apex:insert name="meal" />
25        <br />      
26        <p>That's everything, right?</p>
27        <apex:commandButton action="{!save}" value="Save" id="saveButton"/>
28    </apex:form>
29</apex:page>
Notice the two <apex:insert> fields requiring the age and meal content. The markup for these fields is defined in whichever page calls this composition template.
Next, create a page called myFullForm, which defines the <apex:insert> tags in myFormComposition:
1swfobject.registerObject("clippy.codeblock-3", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<apex:page controller="compositionExample">
18    <apex:messages/>
19    <apex:composition template="myFormComposition">
20    
21    <apex:define name="meal">
22        <apex:outputLabel value="Enter your favorite meal: " for="mealField"/>
23        <apex:inputText id="mealField" value="{!mealField}"/>
24    </apex:define>
25
26    <apex:define name="age">
27        <apex:outputLabel value="Enter your age: " for="ageField"/>
28        <apex:inputText id="ageField" value="{!ageField}"/>
29    </apex:define>
30    
31   <apex:outputLabel value="Enter your favorite color: " for="colorField"/>
32   <apex:inputText id="colorField" value="{!colorField}"/>
33    
34    </apex:composition>
35    
36    <apex:outputText id="greeting" rendered="{!showGreeting}" value="Hello {!nameField}. 
37    You look {!ageField} years old. Would you like some {!colorField} {!mealField}?"/>
38</apex:page>
Notice the following about the markup:
  • When you save myFullForm, the previously defined <apex:inputText> tags and Save button appear.
  • Since the composition page requires age and meal fields, myFullForm defines them as text input fields. The order in which they appear on the page does not matter; myFormComposition specifies that the age field is always displayed before the meal field.
  • The name field is still imported, even without a matching <apex:define> field.
  • The color field is disregarded, even though controller code exists for the field. This is because the composition template does not require any field named color.
  • The age and meal fields do not need to be text inputs. The components within an <apex:define> tag can be any valid Visualforce tag.
To show how you can use any valid Visualforce in an <apex:define> tag, create a new Visualforce page called myAgelessForm and use the following markup:
1swfobject.registerObject("clippy.codeblock-4", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<apex:page controller="compositionExample">
18    <apex:messages/>
19    <apex:composition template="myFormComposition">
20    
21    <apex:define name="meal">
22        <apex:outputLabel value="Enter your favorite meal: " for="mealField"/>
23        <apex:inputText id="mealField" value="{!mealField}"/>
24    </apex:define>
25
26    <apex:define name="age">
27        <p>You look great for your age!</p>
28    </apex:define>
29
30    </apex:composition>
31    
32    <apex:outputText id="greeting" rendered="{!showGreeting}" value="Hello {!nameField}. 
33    Would you like some delicious {!mealField}?"/>
34</apex:page>
Notice that the composition template only requires an <apex:define> tag to exist. In this example, age is defined as text.

Dynamic Templates

A dynamic template allows you to assign a template through a PageReference. The template name is assigned to a controller method that returns a PageReference containing the template you want to use.

For example, create a page called myAppliedTemplate that defines the skeleton template:
1<apex:page>
2    <apex:insert name="name" />
3</apex:page>
Next, create a controller called dynamicComposition with a method that will return a reference to this page:
1public class dynamicComposition {
2    public PageReference getmyTemplate() {
3        return Page.myAppliedTemplate;
4    }
5}
Last, create a page called myDynamicComposition that implements this controller and the dynamic template:
1<apex:page controller="dynamicComposition">
2    <apex:composition template="{!myTemplate}">
3    <apex:define name="name">
4        Hello {!$User.FirstName}, you look quite well.
5    </apex:define>
6    </apex:composition>
7</apex:page>