Custom Components in Visualforce

Exclusive offer: get 50% off this eBook here
Visualforce Development Cookbook

Visualforce Development Cookbook — Save 50%

Over 75 recipes to help you create powerful custom pages, simplify data-entry, and enrich the Salesforce user interface with this book and ebook

$29.99    $15.00
by Keir Bowden | October 2013 | Cookbooks Enterprise Articles Web Development

The article Custom Components in Visualforce by Keir Bowden, author of the book Visualforce Development Cookbook, demonstrates how easy it is to build interactive pages using Visualforce. This article also demonstrates how to create custom Visualforce components for re-use across multiple pages.

In this article, we will cover the following recipes:

  • Passing attributes to components
  • Updating attributes in component controllers
  • Passing action methods to components
  • Data-driven decimal places
  • The custom iterator component
  • Setting a value into a controller property
  • Multiselecting related objects
  • Notifying the containing page controller

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

Visualforce Development Cookbook Over 75 recipes to help you create powerful custom pages, simplify data-entry, and enrich the Salesforce user interface with this book and ebook
Published: September 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

The custom iterator component

The Visualforce standard component <apex:repeat /> iterates a collection of data and outputs the contained markup once for each element in the collection. In the scenario where this is being used to display a table of data, the markup for the table headings appears before the <apex:repeat /> component and is rendered regardless of whether the collection contains any records or not.

Custom iterator components may contain additional markup to be rendered outside the collection, for example, the headings markup in the scenario mentioned earlier. This allows the component to avoid rendering any markup if the collection is empty through the logic implemented in a custom controller.

In this recipe, we will create a custom component that takes a collection of data and renders a containing page block and a page block section for each element in the collection. If the collection is empty, no markup will be rendered. We will also create a containing page that displays the details of an sObject account and utilizes the custom component to display contact and opportunity information, if present.

Getting ready

This recipe makes use of a custom controller, so this will need to be present before the custom component can be created.

How to do it…

  1. Navigate 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 AllOrNothingController.cls Apex class from the code download into the Apex Class area.
  4. Click on the Save button.
  5. Navigate to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  6. Click on the New button.
  7. Enter AllOrNothingPageBlock in the Label field.
  8. Accept the default AllOrNothingPageBlock that is automatically generated for the Name field.
  9. Paste the contents of the AllOrNothingPageBlock.component file from the code download into the Visualforce Markup area and click on the Save button.
  10. Next, create the custom controller for the Visualforce page 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 AllOrNothingListsExt.cls Apex class from the code download into the Apex Class area.
  13. Click on the Save button.
  14. Next, create the 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 AllOrNothingLists in the Label field.
  17. Accept the default AllOrNothingLists that is automatically generated for the Name field.
  18. Paste the contents of the AllOrNothingLists.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 AllOrNothingLists page 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 AllOrNothingLists page: https://<instance>/apex/AllOrNothingLists?id=<account_id>.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com, and <account_id> is the ID of an account from your Salesforce instance.

The page displays brief details of the account and page blocks for the account's contacts and opportunities.

If the account does not have any opportunities or contacts, the appropriate page block is omitted.

The AllOrNothingPageBlock custom component accepts a list of generic sObjects and wraps its content in an output panel that is only rendered if the list is not empty.

<apex:outputPanel rendered="{!render}"> <apex:pageBlock title="{!title}"> <apex:repeat value="{!list}" var="ele"> <apex:componentBody > <apex:variable var="{!var}" value="{!ele}"/> </apex:componentBody> </apex:repeat> </apex:pageBlock> </apex:outputPanel>

The <apex:componentBody /> defines where the content from the Visualforce page will be inserted. As this is inside the <apex:repeat /> component, this insertion will take place for each element in the collection.

The Visualforce page passes attributes to the component of the list to iterate the title of the page block, and the variable name representing an element in the list. The contained markup can reference the variable name to access fields or properties of the element.

<c:AllOrNothingPageBlock list="{!opportunities}" var="opp" title="Opportunities"> <apex:pageBlockSection title="{!opp.Name}"> <apex:outputField value="{!opp.Amount}" /> <apex:outputField value="{!opp.CloseDate}" /> <apex:outputField value="{!opp.StageName}" /> <apex:outputField value="{!opp.Probability}" /> </apex:pageBlockSection> </c:AllOrNothingPageBlock>

Setting a value into a controller property

Visualforce controllers are often re-used across pages with minor variations in behavior specific to the page, for example, displaying accounts of a particular type. While the controller can detect the page that it is being used by and alter its behavior accordingly, this is not a particularly maintainable solution, as use of the controller in any new page would require changes to the Apex code and renaming a page would break the functionality.

A better mechanism is for the page to set the values of properties in the controller to indicate the desired behavior. In this recipe we will create a custom component that takes two attributes: a value and the controller property to set the value into. Two Visualforce pages with a common controller will also be created to demonstrate how the component can be used to change the behavior of the controller to suit the page.

Getting ready

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

How to do it…

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

How it works…

Opening the first Visualforce page in your browser displays a list of accounts whose type is Customer - Direct: https://<instance>/apex/AccountsType1.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

While, opening the second Visualforce page displays a list of accounts whose type is Customer - Channel: https://<instance>/apex/AccountsType2.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

The SetControllerProperty custom component assigns the value attribute to the controller property attribute:

<apex:component > <apex:attribute name="from" type="String" assignTo="{!to}" description="The value to set"/> <apex:attribute name="to" type="String" description="The controller property to set the value into"/> </apex:component>

The Visualforce pages set the type of account to be retrieved into the controller property via the custom component.

<c:SetControllerProperty from="Customer - Direct" to="{!accType}" />

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.
  • The Passing attributes to components recipe in this article shows how an sObject may be passed as an attribute to a custom component.

Multiselecting related objects

One task that users often find unwieldy when implementing Salesforce is setting up the sObjects to represent many-to-many relationships. A junction object allows a single instance of one sObject type to be related to multiple instances of another sObject type and vice versa.

This requires the user to create a new instance of the junction object and populate master-detail fields to associate two sObjects with each other, resulting in a large number of clicks and page transitions.

In this recipe, we will create a custom object – account group – that acts as a container for multiple accounts. We will then create a page that allows a number of accounts to be associated with a single custom sObject. We will use junction objects for the relationship to allow a single account to be related to multiple account groups, and a single account group to be associated with multiple accounts. A custom Visualforce component will manage the action of presenting the available accounts and allowing the user to choose which to relate with the account group. The component will use the mechanism described in the Updating attributes in component controllers recipe to make the selected values available to the page controller via a custom string container class.

Getting ready

This recipe requires two custom sObjects: the account group, and the junction object between an account group and an account.

  1. First, create the account group custom sObject by navigating to Your Name | Setup | Develop | Objects.
  2. Click on the New Custom Object button.
  3. Enter Account Group in the Label field.
  4. Enter Account Groups in the Plural Label field.
  5. Select the Starts with vowel sound box.
  6. Leave all other input values at their defaults and click on the Save button.
  7. Next, create the junction object to associate an account group with an account by navigating to Your Name | Setup | Develop | Objects.
  8. Click on the New Custom Object button.
  9. Enter Account Group JO in the Label field.
  10. Enter Account Group JOs in the Plural Label field.
  11. Select the Starts with vowel sound box.
  12. Leave all other input values at their defaults and click on the Save button.
  13. On the resulting page, create the master-detail relationship for the account group by scrolling down to the Custom Fields and Relationships section and clicking on the New button.
  14. On the next page, Step 1. Choose the field type, select the Master-Detail Relationship from the Data Type radio buttons and click on the Next button.
  15. On the next page, Step 2. Choose the related object, choose Account Group from the Related To picklist and click on the Next button.
  16. On the next page, Step 3. Enter the label and name for the lookup field, leave all the fields at their default values and click on the Next button.
  17. On the next page, Step 4. Establish field-level security for reference field, leave all the fields at their default values and click on the Next button.
  18. On the next page, Step 5. Add reference field to page layouts, leave all the fields at their default values and click on the Next button.
  19. On the final page, Step 6. Add Custom Related Lists, leave all the fields at their default values and click on the Save button.
  20. Next, create the master-detail relationship for the account by scrolling down to the Custom Fields and Relationships section and click on the New button.
  21. On the next page, Step 1. Choose the field type, select the Master-Detail Relationship from the Data Type radio buttons and click on the Next button.
  22. On the next page, Step 2. Choose the related object, choose Account from the Related To picklist and click on the Next button.
  23. On the next page, Step 3. Enter the label and name for the lookup field, leave all the fields at their default values and click on the Next button.
  24. On the next page, Step 4. Establish field-level security for reference field, leave all the fields at their default values and click on the Next button.
  25. On the next page, Step 5. Add reference field to page layouts, leave all the fields at their default values and click on the Next button.
  26. On the final page, Step 6. Add Custom Related Lists, leave all the fields at their default values and click on the Save button.

How to do it…

  1. Create the custom string container class 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 StringContainer.cls Apex class from the code download into the Apex Class area.
  4. Click on the Save button.
  5. Next, create the custom controller for the Visualforce component by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  6. Click on the New button.
  7. Paste the contents of the MultiSelectRelatedController.cls Apex class from the code download into the Apex Class area.
  8. Click on the Save button.
  9. Next, navigate to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  10. Click on the New button.
  11. Enter MultiSelectRelated in the Label field.
  12. Accept the default MultiSelectRelated that is automatically generated for the Name field.
  13. Paste the contents of the MultiSelectRelated.component file from the code download into the Visualforce Markup area and click on the Save button.
  14. Next, create the custom controller for the Visualforce page by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  15. Click on the New button.
  16. Paste the contents of the AccountGroupController.cls Apex class from the code download into the Apex Class area.
  17. Click on the Save button.
  18. Finally, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  19. Click on the New button.
  20. Enter AccountGroup in the Label field.
  21. Accept the default AccountGroup that is automatically generated for the Name field.
  22. Paste the contents of the AccountGroup.page file from the code download into the Visualforce Markup area and click on the Save button.
  23. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  24. Locate the entry for the AccountGroup page and click on the Security link.
  25. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the Visualforce page in your browser displays the account group create page: https://<instance>/apex/AccountGroup.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

The chosen account IDs are stored as semi-colon separated values in a property of the page controller. The page controller constructor extracts all accounts and creates a standard SelectOption class for each one.

accountOptions=new List<SelectOption>(); for (Account acc : [select id, Name from Account]) { accountOptions.add(new SelectOption(acc.id, acc.name)); }

The custom component controller contains two collections of options: available and chosen. The component iterates the full set of account options and adds the option to available or chosen depending on whether the account ID is present in the semi-colon separated string of chosen IDs.

availableItems=new List<SelectOption>(); chosenItems=new List<SelectOption>(); for (SelectOption sel : allOptions) { String selId=sel.getValue(); if (selected.value.contains(selId+';')) { chosenItems.add(sel); } else { availableItems.add(sel); } }

Accounts can be moved between the Available and Selected lists by highlighting the options and clicking on the > or < buttons.

Each button invokes an action method in the component controller that adds or removes the account IDs from the semi-colon separated chosen string, and then rebuilds the available and chosen lists.

Clicking on the Save button creates the account group record and a junction object for each account ID in the chosen string.

public PageReference save() { insert accountGroup; List<Account_Group_JO__c> agJOs= new List<Account_Group_JO__c>(); for (String accId : chosenAccounts.value.split(';')) { Account_Group_JO__c agJO= new Account_Group_JO__c( Account_Group__c=accountGroup.id, Account__c=accId); agJOs.add(agJO); } insert agJOs; return new PageReference('/' + accountGroup.id); }

Notifying the containing page controller

In the earlier recipes, we have seen how components can accept an attribute that is a property from the containing page controller and update the value of the property in response to a user action. If the containing page controller needs to determine if the property has changed, it must capture the previous value of the property and compare that with the current value. The same applies if the attribute passed to the component is a field from an sObject managed by the parent page controller.

In this recipe we will create a custom component that can notify its containing page controller when an attribute value is changed. In order to avoid tying the component to a particular page controller class, we will create an interface that defines the method to be used to notify the page controller. This will allow the component controller to notify any page controller that implements the interface.

Interfaces define a "contract" between the calling code and the implementing code. The calling code is able to rely on the method(s) defined in the interface being available without having to know the details of the underlying code that is implementing the interface. This allows the implementing code to be swapped in and out without affecting the calling code.

Getting ready

This recipe requires that you have already completed the Multiselecting related objects recipe, as it relies on the custom sObjects created in that recipe.

How to do it…

  1. First, create the interface 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 Notifiable.cls Apex class from the code download into the Apex Class area.
  4. Click on the Save button.
  5. Next, create the component controller by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  6. Click on the New button.
  7. Paste the contents of the NotifyingMultiSelectRelatedController.cls Apex class from the code download into the Apex Class area.
  8. Click on the Save button.
  9. Next, create the custom component by navigating to the Visualforce Components setup page by clicking on Your Name | Setup | Develop | Components.
  10. Click on the New button.
  11. Enter NotifyingMultiSelectRelated in the Label field.
  12. Accept the default NotifyingMultiSelectRelated that is automatically generated for the Name field.
  13. Paste the contents of the NotifyingMultiSelectRelated.component file from the code download into the Visualforce Markup area and click on the Save button.
  14. Next, create the custom controller for the Visualforce page by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.
  15. Click on the New button.
  16. Paste the contents of the NotifiableAccountGroupController.cls Apex class from the code download into the Apex Class area.
  17. Click on the Save button.
  18. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  19. Click on the New button.
  20. Enter NotifiableAccountGroup in the Label field.
  21. Accept the default NotifiableAccountGroup that is automatically generated for the Name field.
  22. Paste the contents of the NotifiableAccountGroup.page file from the code download into the Visualforce Markup area and click on the Save button.
  23. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.
  24. Locate the entry for the NotifiableAccountGroup page and click on the Security link.
  25. 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 NotifiableAccountGroup page: https://<instance>/apex/NotifiableAccountGroup.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com, and <account_id> is the ID of an account from your Salesforce instance.

When accounts are moved between the Available and Selected lists, the component controller notifies the parent page controller, which writes a message into the page with the notification details.

The parent page controller, NotifiableAccountGroupController, implements the Notifiable interface.

public with sharing class NotifiableAccountGroupController implements Notifiable

The implementation of the notify method wraps the notification text in an ApexPages.Message class and adds this to the messages for the page.

public void notify(String detail) { ApexPages.addMessage(new ApexPages.Message( ApexPages.Severity.INFO, 'Notified - ' + detail)); }

The custom component takes a parameter of type Notifiable, which is assigned to a property in its controller.

<apex:attribute name="notify" description="The entity to notify when the selection changes" type="Notifiable" assignTo="{!notifiable}" />

The custom component also takes a rerender parameter, which is used to update part of the containing page when the selection changes.

<apex:attribute name="rerender" description="The component to rerender when the selection changes" type="String" />

In this case, the page passes through the ID of its <apex:pageMessages /> component to display the message added in the page controller's notify method as described earlier.

When the action methods to move accounts between the Available and Selected lists are executed, these invoke the notify method with details of the change.

if (null!=notifiable) { notifiable.notify('Values deleted - now ' + selected.value); }

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.
  • The Passing attributes to components recipe in this article shows how an sObject may be passed as an attribute to a custom component.
  • The Multiselecting related objects in this article shows how to create a custom multiselect picklist style component.

Summary

This article provided us the details on creating custom components to encapsulate features and functionalities that can be re-used across multiple pages. Also, this article covers the explanation for communication between components and page controllers.

Resources for Article:


Further resources on this subject:


Visualforce Development Cookbook Over 75 recipes to help you create powerful custom pages, simplify data-entry, and enrich the Salesforce user interface with this book and ebook
Published: September 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Keir Bowden

Keir Bowden is a 25-year veteran of the IT industry from the United Kingdom. After spending the early part of his career in the Defense industry, he moved into investment-banking systems, implementing systems for Banque Nationale de Paris, CitiGroup, and Deutsche Bank. In the late 1990s, Keir moved into Internet technologies, leading the development of the order management and payment handling systems of one of the first European Internet shopping sites.

Keir started working with Force.com in late 2008 and has been recognized by Salesforce as a Force.com MVP for contribution and leadership in the community. In 2011, he became one of the selected few people worldwide to earn all Salesforce.com certifications, and now serves as a judge on the EMEA Technical Architect Certification Review Boards. Keir is also a prominent blogger on Apex and Visualforce solutions, and regular speaker at events such as Dreamforce and Cloudstock.

Keir is a Chief Technical Officer of BrightGen, a Salesforce.com Platinum Cloud Alliance Partner in the United Kingdom, where he is responsible for current and future technical strategy.

Keir worked as the technical reviewer for Salesforce CRM Admin Cookbook by Packt Publishing before accepting the challenge of authoring his first book.

Books From Packt


Visualforce Developer’s guide
Visualforce Developer’s guide

 Force.com Tips and Tricks
Force.com Tips and Tricks

Salesforce CRM: The Definitive Admin Handbook - Second Edition
Salesforce CRM: The Definitive Admin Handbook - Second Edition

 Salesforce CRM: The Definitive Admin Handbook
Salesforce CRM: The Definitive Admin Handbook

 Salesforce CRM Admin Cookbook
Salesforce CRM Admin Cookbook

Force.com Developer Certification Handbook (DEV401)
Force.com Developer Certification Handbook (DEV401)

Oracle APEX Best Practices
Oracle APEX Best Practices

 Oracle APEX 4.0 Cookbook
Oracle APEX 4.0 Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software