14 min read

(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:

  • Functional decomposition, where a lengthy page is broken down into custom components to make it easier to develop and maintain
  • Code re-use, where a custom component provides common functionality that can be re-used across a number of pages

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.

Passing attributes to components

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.

How to do it…

This recipe does not require any Apex controllers, so we can start with the custom component.

  1. Navigate to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  2. Click on the New button.
  3. Enter ContactNameEdit in the Label field.
  4. Accept the default ContactNameEdit that is automatically generated for the Name field.
  5. Paste the contents of the ContactNameEdit.component file from the code download into the Visualforce Markup area and click on the Save button.

    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.

  6. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  7. Click on the New button.
  8. Enter ContactEdit in the Label field.
  9. Accept the default Contact Edit that is automatically generated for the Name field.
  10. Paste the contents of the ContactEdit.page file from the code download into the Visualforce Markup area and click on the Save button.
  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  12. Locate the entry for the Contact Edit page and click on the Security link.
  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

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}”/>


See also

  • The Updating attributes in component controllers recipe in this article shows how a custom component can update an attribute that is a property of the enclosing page controller.

Updating attributes in component controllers

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.

Getting ready

This recipe requires a custom Apex class to encapsulate the Date primitive. To do so, perform the following steps:

  1. First, create the class that encapsulates the Date primitive by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  2. Click on the New button.
  3. Paste the contents of the DateContainer.cls Apex class from the code download into the Apex Class area.
  4. Click on the Save button.

How to do it…

  1. First, create the custom component controller by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  2. Click on the New button.
  3. Paste the contents of the DateEditController.cls Apex class from the code download into the Apex Class area.
  4. Click on the Save button.
  5. Next, create the custom component by navigating to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  6. Click on the New button.
  7. Enter DateEdit in the Label field.
  8. Accept the default DateEdit that is automatically generated for the Name field.
  9. Paste the contents of the DateEdit.component file from the code download into the Visualforce Markup area and click on the Save button.
  10. Next, create the Visualforce page controller extension by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  11. Click on the New button.
  12. Paste the contents of the ContactDateEditExt.cls Apex class from the code download into the Apex Class area.
  13. Click on the Save button.
  14. Finally, create a Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  15. Click on the New button.
  16. Enter ContactDateEdit in the Label field.
  17. Accept the default ContactDateEdit that is automatically generated for the Name field.
  18. Paste the contents of the ContactDateEdit.page file from the code download into the Visualforce Markup area and click on the Save button.
  19. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  20. Locate the entry for the ContactDateEdit.page file and click on the Security link.
  21. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

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:

  • A required attribute of type DateContainer, which is assigned to the dateContainer property of the controller
  • The title of for the page block section that will house the picklists; as this is a reusable component, the page supplies an appropriate title

    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(); }


See also

  • The Passing attributes to components recipe in this article shows how an sObject may be passed as an attribute to a custom component.

Passing action methods to components

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.

How to do it…

This recipe does not require any Apex controllers, so we can start with the custom component.

  1. Navigate to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  2. Click on the New button.
  3. Enter ContactEdit in the Label field.
  4. Accept the default ContactEdit that is automatically generated for the Name field.
  5. Paste the contents of the ContactEdit.component file from the code download into the Visualforce Markup area and click on the Save button.
  6. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  7. Click on the New button.
  8. Enter ContactEditActions in the Label field.
  9. Accept the default ContactEditActions that is automatically generated for the Name field.
  10. Paste the contents of the ContactEditActions.page file from the code download into the Visualforce Markup area and click on the Save button.
  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  12. Locate the entry for the ContactEditActions page and click on the Security link.
  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

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” />


There’s more…

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.

See also

  • The Updating attributes in component controllers recipe in this article shows how a custom component can update an attribute that is a property of the enclosing page controller.

Data-driven decimal places

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.

How to do it…

This recipe does not require any Apex controllers, so we can start with the custom component.

  1. Navigate to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  2. Click on the New button.
  3. Enter DecimalPlaces in the Label field.
  4. Accept the default DecimalPlaces that is automatically generated for the Name field.
  5. Paste the contents of the DecimalPlaces.component file from the code download into the Visualforce Markup area and click on the Save button.
  6. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  7. Click on the New button.
  8. Enter DecimalPlacesDemo in the Label field.
  9. Accept the default DecimalPlacesDemo that is automatically generated for the Name field.
  10. Paste the contents of the DecimalPlacesDemo.page file from the code download into the Visualforce Markup area and click on the Save button.
  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  12. Locate the entry for the DecimalPlacesDemo page and click on the Security link.
  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

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>


LEAVE A REPLY

Please enter your comment!
Please enter your name here