Learning Objectives

After completing this unit, you’ll be able to:
  • Explain the difference between coarse-grained and fine-grained components, and why you might want to use one or the other.
  • Explain what an iteration component is and what it’s used for.
  • Use relevant coarse-grained components to display record details and related lists.
  • Use relevant fine-grained components to replace and customize coarse-grained components.

Introduction to Output Components

Visualforce includes nearly 150 built-in components that you can use on your pages. Components are rendered into HTML, CSS, and JavaScript when a page is requested. Coarse-grained components provide a significant amount of functionality in a single component, and might add a lot of information and user interface to the page it’s used on. Fine-grained components provide more focused functionality, and enable you to design the page to look and behave the way you want.

Here we’ll focus on output components, that is, components that output data from a record and enable you to design a view-only user interface.

Create a Visualforce Page with a Standard Controller

Use output components with a standard controller to make it easy to access and display record details.

You’ll experiment with a number of different output components in this page. For now, let’s create a mostly blank page.

  1. Open the Developer Console and click File | New | Visualforce Page to create a new Visualforce page. Enter AccountDetail for the page name.
  2. In the editor, replace any markup with the following.
    <apex:page standardController="Account">
        
        {! Account.Name }
        
    </apex:page>
  3. Click Preview to open a preview of your page that you can look at while you make changes.
    A new window should open, showing the standard Salesforce page header and sidebar elements, but nothing in the body.
  4. In the preview window, add the ID for an account to the URL, and press Return.
    The URL should be something like this: https://SalesforceInstance/apex/AccountDetail?core.apexpages.request.devconsole=1&id=001D000000JRBes
    You should now see the name of the account in the body. This verifies that you’ve got the standard controller working and a valid record ID.

Display Record Details

Use <apex:detail> to quickly add record details to a page that uses a standard controller.

Some output components bring a lot to the party. These “coarse grained” components offer a lot of functionality, displaying many fields, labels, and other user interface elements. They let you quickly build pages that are variations on the built-in Salesforce user interface.

  1. Replace the line with {! Account.Name } with the following markup, and save your changes.
    <apex:detail />
    Wow, that is a big change! With one line of markup you’ve just reproduced the entire standard view page for the account object!
    The <apex:detail/> component

<apex:detail> is a coarse-grained output component that adds many fields, sections, buttons, and other user interface elements to the page in just one line of markup. Notice also that everything it adds to the page uses the Salesforce Classic styling. There are quite a few attributes for customizing the appearance of <apex:detail>. Spend a few minutes now and try changing a few to see what they do.

Display Individual Fields

Use <apex:outputField> to display individual fields from a record.

When you need even more control over your page layout, you can add fields individually. The <apex:outputField> component is designed for doing exactly that.

  1. Replace the <apex:detail/> line with the following markup.
    <apex:outputField value="{! Account.Name }"/>
    <apex:outputField value="{! Account.Phone }"/>
    <apex:outputField value="{! Account.Industry }"/>
    <apex:outputField value="{! Account.AnnualRevenue }"/>
    
    The four fields are added to the page. But the formatting perhaps isn’t what you expected.
    Output fields, outside of a page block
    The field values are displayed all on one line, without labels, and without other formatting. That’s not what we want, and it’s quite a contrast to the <apex:detail> and <apex:relatedList> components, which automatically use the platform styling.

    By itself, the <apex:outputField> only outputs the field’s value. But when you wrap it in <apex:pageBlock> and <apex:pageBlockSection> components, its behavior changes quite a bit.

  2. Wrap the <apex:outputField> lines with <apex:pageBlock> and <apex:pageBlockSection> components, so that your markup looks like this.
    <apex:pageBlock title="Account Details">
        <apex:pageBlockSection>
            <apex:outputField value="{! Account.Name }"/>
            <apex:outputField value="{! Account.Phone }"/>
            <apex:outputField value="{! Account.Industry }"/>
            <apex:outputField value="{! Account.AnnualRevenue }"/>
        </apex:pageBlockSection>
    </apex:pageBlock>
    That’s more like it!
    Output fields inside a page block
    The <apex:pageBlock> and <apex:pageBlockSection> components are required to activate the platform look and feel. When you use <apex:outputField> within a <apex:pageBlockSection> it adopts the two column layout, adds field labels, aligns and styles fields and labels nicely, and so on.

Although <apex:outputField> seems like a fine-grained component because it only outputs one field, it’s actually doing quite a lot. It knows if it’s being used inside certain other components, and changes its output and styling appropriately. It’s also smart about formatting and display. Notice that the Annual Revenue field is formatted as currency. <apex:outputField> automatically adapts to the data type of the field being displayed. Try adding a date, checklist, or picklist field to the page, and see what happens.

Display A Table

Use <apex:pageBlockTable> to add a table of data to a page.
What exactly is a related list? What does <apex:relatedList> do when you add it to a page?
  • It grabs a list of similar data elements. For example, a list of contacts for the account.
  • It sets up a table with columns for each field, headers atop each column, and so on.
  • For each item in the list—for each related contact—it adds a row to the table, and fills in each column with the appropriate field from that record.

You can do the same thing in your own Visualforce markup using iteration components. An iteration component works with a collection of similar items, instead of on a single value. For example, {!Account.contacts} is an expression that evaluates to a list of contacts for an account. You can use this expression with an iteration component to create a list or table with details of these related contacts.

  1. Replace the two <apex:relatedList/> lines with the following markup.
    <apex:pageBlock title="Contacts">
       <apex:pageBlockTable value="{!Account.contacts}" var="contact">
          <apex:column value="{!contact.Name}"/>
          <apex:column value="{!contact.Title}"/>
          <apex:column value="{!contact.Phone}"/>
       </apex:pageBlockTable>
    </apex:pageBlock>
    A table listing the account’s contacts is added to the page, with just the columns you’ve chosen.
    Contacts list using pageBlockTable
<apex:pageBlockTable> is an iteration component that generates a table of data, complete with platform styling. Here’s what’s going on in your markup.
  • The value attribute of <apex:pageBlockTable> is set to the expression mentioned previously, {!Account.contacts}. This is the list of records that <apex:pageBlockTable> will work with.
  • For each record in that list, one record at a time, <apex:pageBlockTable> assigns that record to the variable named in the <apex:pageBlockTable>’s var attribute. In this case, that variable is named contact.
  • For each record, <apex:pageBlockTable> constructs a new row in the table, using the row defined by the set of <apex:column>components within the body of <apex:pageBlockTable>. The <apex:column> components, in turn, use the contact variable that represents the current record to pull out the field values for that record.
  • Outside of the loop, <apex:pageBlockTable> uses the fields in the <apex:column> components to create column headers, by looking up the label for each field.

That’s a lot to take in, and iteration components are tricky to understand the first time. The best thing you can do right now is to try creating your own. Add a list of opportunity related records to the page using <apex:pageBlockTable>. Choose the fields you want displayed in the table. Look up the different attributes for <apex:pageBlockTable> and <apex:column>, and experiment until you feel comfortable.

Tell Me More...

Coarse-grained components let you quickly add lots of functionality to a page, while fine-grained components give you more control over the specific details of a page.

<apex:enhancedList> and <apex:listViews> are other coarse-grained components that you might want to use with or in place of <apex:relatedList>. And there are many other components that pack a lot of functionality into a single tag. If you haven’t done it yet, check out the Standard Component Reference and see what the range of possibilities are.

<apex:pageBlockTable> is an iteration component that picks up the platform styling. <apex:dataTable> and <apex:dataList> are iteration components for creating tables and lists without the platform styling. And <apex:repeat> is an iteration component that you can use to generate any arbitrary markup for a collection of records.

You may have noticed that your manually created related lists are missing some things that were added to the table created by <apex:relatedList>. For example, the Edit and Del links to edit and delete individual records is missing, and so is the New Contact button. To create these user interface elements you need to know a little more Visualforce, specifically about forms and actions. You’ll learn about that elsewhere.

Share Time Estimate

Having trouble with your challenge verification?

Here are some tips:

  1. Check for typos (hey, it happens)
  2. Try using a new Developer Edition (existing customizations can interfere with the validation)