





















































(For more resources related to this topic, see here.)
Custom components allow custom Visualforce functionality to be encapsulated as discrete modules, which provides two main benefits:
A custom component may have a controller, but unlike Visualforce pages, only custom controllers may be used. A custom component can also take attributes, which can influence the generated markup or set property values in the component's controller.
Custom components do not have any associated security settings; a user with access to a Visualforce page has access to all custom components referenced by the page.
Visualforce pages can pass parameters to components via attributes. A component declares the attributes that it is able to accept, including information about the type and whether the attribute is mandatory or optional. Attributes can be used directly in the component or assigned to properties in the component's controller.
In this recipe we will create a Visualforce page that provides contact edit capability. The page utilizes a custom component that allows the name fields of the contact, Salutation, First Name , and Last Name, to be edited in a three-column page block section. The contact record is passed from the page to the component as an attribute, allowing the component to be re-used in any page that allows editing of contacts.
This recipe does not require any Apex controllers, so we can start with the custom component.
Once a custom component is saved, it is available in your organization's component library, which can be accessed from the development footer of any Visualforce page. For more information visit http://www.salesforce.com/us/developer/docs/pages/Content/pages_quick_start_component_library.htm.
Opening the following URL in your browser displays the ContactEdit page: https://<instance>/apex/ContactEdit.
Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.
The custom component that renders the input fields in the Name section defines a single, required attribute of type Contact.
<apex:attribute name="Contact" type="Contact" description="The contact to edit" required="true" />
The description of the attribute must always be provided, as this is included in the component reference. The type of the attribute must be a primitive, sObject, one-dimensional list, map, or custom Apex class.
The Contact attribute can then be used in merge syntax inside the component.
<apex:inputField value="{!Contact.Salutation}"/> <apex:inputField value="{!Contact.FirstName}"/> <apex:inputField value="{!Contact.LastName}"/>
The page passes the contact record being managed by the standard controller to the component via the Contact attribute.
<c:ContactNameEdit contact="{!Contact}"/>
Updating fields of sObjects passed as attributes to custom components is straightforward, and can be achieved through simple merge syntax statements. This is not so simple when the attribute is a primitive and will be updated by the component controller, as parameters are passed by value, and thus, any changes are made to a copy of the primitive. For example, passing the name field of a contact sObject, rather than the contact sObject itself, would mean that any changes made in the component would not be visible to the containing page.
In this situation, the primitive must be encapsulated inside a containing class. The class instance attribute is still passed by value, so it cannot be updated to point to a different instance, but the properties of the instance can be updated.
In this recipe, we will create a containing class that encapsulates a Date primitive and a Visualforce component that allows the user to enter the date via day/month/year picklists. A simple Visualforce page and controller will also be created to demonstrate how this component can be used to enter a contact's date of birth.
This recipe requires a custom Apex class to encapsulate the Date primitive. To do so, perform the following steps:
Opening the following URL in your browser displays the ContactDateEdit page: https://<instance>/apex/ContactDateEdit?id=<contact_id>.
Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com, and <contact_id> is the ID of any contact in your Salesforce instance.
The Visualforce page controller declares a DateContainer property that will be used to capture the contact's date of birth.
public DateContainer dob {get; set;} private Contact cont; private ApexPages.StandardController stdCtrl {get; set;} public ContactDateEditExt(ApexPages.StandardController std) { stdCtrl=std; cont=(Contact) std.getRecord(); dob=new DateContainer(cont.BirthDate); }
Note that as DateContainer is a class, it must be instantiated when the controller is constructed.
The custom component that manages the Date of Birth section defines the following two attributes:
Note that this component is not tightly coupled with a contact date of birth field; it may be used to manage a date field for any sObject.
<apex:attribute type="DateContainer" name="dateContainerAtt" description="The date" assignTo="{!dateContainer}" required="true" /> <apex:attribute type="String" description="Page block section title" name="title" />
The component controller defines properties for each of the day, month, and year elements of the date. Each setter for these properties attempts to construct the date if all of the other elements are present. This is required as there is no guarantee of the order in which the setters will be called when the Save button is clicked and the postback takes place.
public Integer year {get; set { year=value; updateContainer(); } } private void updateContainer() { if ( (null!=year) && (null!=month) && (null!=day) ) { Date theDate=Date.newInstance(year, month, day); dateContainer.value=theDate; } }
When the contained date primitive is changed in the updateContainer method, this is reflected in the page controller property, which can then be used to update a field in the contact record.
public PageReference save() { cont.BirthDate=dob.value; return stdCtrl.save(); }
A controller action method is usually invoked from the Visualforce page that it is providing the logic for. However, there are times when it is useful to be able to execute a page controller action method directly from a custom component contained within the page. One example is for styling reasons, in order to locate the command button that executes the action method inside the markup generated by the component.
In this recipe we will create a custom component that provides contact edit functionality, including command buttons to save or cancel the edit, and a Visualforce page to contain the component and supply the action methods that are executed when the buttons are clicked.
This recipe does not require any Apex controllers, so we can start with the custom component.
Opening the following URL in your browser displays the ContactEditActions page: https://<instance>/apex/ContactEditActions?id=<contact_id>.
Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com, and <contact_id> is the ID of any contact in your Salesforce instance.
The Visualforce page simply includes the custom component, and passes the Save and Cancel methods from the standard controller as attributes.
<apex:page standardController="Contact"> <apex:pageMessages /> <apex:form > <c:ContactEdit contact="{!contact}" saveAction="{!save}" cancelAction="{!cancel}" /> </apex:form> </apex:page>
The ContactEdit custom component declares attributes for the action methods of type ApexPages.Action.
<apex:attribute name="SaveAction" description="The save action method from the page controller" type="ApexPages.Action" required="true"/> <apex:attribute name="CancelAction" description="The cancel action method from the page controller" type="ApexPages.Action" required="true"/>
These attributes can then be bound to the command buttons in the component in the same way as if they were supplied by the component's controller.
<apex:commandButton value="Save" action="{!SaveAction}" /> <apex:commandButton value="Cancel" action="{!CancelAction}" immediate="true" />
While this example has used action methods from a standard controller, any action method can be passed to a component using this mechanism, including methods from a custom controller or controller extension.
Attributes passed to custom components from Visualforce pages can be used wherever the merge syntax is legal. The <apex:outputText /> standard component can be used to format numeric and date values, but the formatting is limited to literal values rather than merge fields. In this scenario, an attribute indicating the number of decimal places to display for a numeric value cannot be used directly in the <apex:outputText /> component.
In this recipe we will create a custom component that accepts attributes for a numeric value and the number of decimal places to display for the value. The decimal places attribute determines which optional component is rendered to ensure that the correct number of decimal places is displayed, and the component will also bracket negative values. A Visualforce page will also be created to demonstrate how the component can be used.
This recipe does not require any Apex controllers, so we can start with the custom component.
Opening the following URL in your browser displays the DecimalPlacesDemo page: https://<instance>/apex/DecimalPlacesDemo.
Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.
The Visualforce page iterates a number of opportunity records and delegates to the component to output the opportunity amount, deriving the number of decimal places from the amount.
<c:DecimalPlaces dp="{!TEXT(MOD(opp.Amount/10000, 5))}" value="{!opp.Amount}" />
The component conditionally renders the appropriate output panel, which contains two conditionally rendered <apex:outputText /> components, one to display a positive value to the correct number of decimal places and another to display a bracketed negative value.
<apex:outputPanel rendered="{!dp=='1'}"> <apex:outputText rendered="{!AND(NOT(ISNULL(VALUE)), value>=0)}" value="{0, number, #,##0.0}"> <apex:param value="{!value}"/> </apex:outputText> <apex:outputText rendered="{!AND(NOT(ISNULL(VALUE)), value<0)}" value="({0, number, #,##0.0})"> <apex:param value="{!ABS(value)}"/> </apex:outputText> </apex:outputPanel>