The Silver Lining

Lessons & Learnings from a salesforce certified technical architect.

Formatting – PageBlockSectionItem, InputField & OutPutField

with 4 comments

There are a collection of forum posts asking why VisualForce formatting isn’t being applied correctly to PageBlockSectionItems and/or InputFields, and the answer isn’t immediately obvious so let’s see what we can throw together.

A Working Sample

We’ll start with a sample page whose formatting is functioning correctly, and then we’ll break it in various ways that’ll help us understand the limitations we need to consider. Our simple page code might be,


<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">
          <apex:pageBlockSection>
              <apex:inputField value="{!Account.name}" />
              <apex:inputField value="{!Account.SLAExpirationDate__c}" />
              <apex:outputField value="{!Account.rating}" />
          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>

Which yields the following UI,

Note the little red bar near the 'Name' input, and the nifty date-picker on the date-type field.

Note that we can use Input/OutputFields because our fields are bound to the Account object. A later example demonstrates what to do if this is not the case.

A Troublesome Modification – The Beginning of a Theory

At this point all is right with the world and our face has a smile a chesire cat would envy. But then someone comes along and asks for just a quick change, the requirements of which makes you realise you need to wrap your fields in an ActionRegion. You expect it to be easy-peasy but after creating the wrapping tag,

<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">
          <apex:pageBlockSection>
              <apex:actionRegion>
                  <apex:inputField value="{!Account.name}" />
                  <apex:inputField value="{!Account.SLAExpirationDate__c}" />
                  <apex:outputField value="{!Account.rating}" />
              </apex:actionRegion>
          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>

You end up with a partially formatted page that looks something like this,

The spacing and labels have left the building!

Your smile will now have vanished, although hope reigns in your heart. A lightbulb appears a-top you head, ‘You simple need to shuffle the tags a bit’ you think smartly to yourself,

<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">
          <apex:actionRegion>
          <apex:pageBlockSection>

              <apex:inputField value="{!Account.name}" />
              <apex:inputField value="{!Account.SLAExpirationDate__c}" />
              <apex:outputField value="{!Account.rating}" />

          </apex:pageBlockSection>
          </apex:actionRegion>
      </apex:pageBlock>
    </apex:form>
</apex:page>

And it does indeed work.. for this example. Looking over your code you start to suspect that if you want your formatting to work you can only use Input/OutputFields inside of PageBlockSections. A good conclusion, unless we modify the requirements, let’s do that now.

A Devilish Modification – PageBlockSectionItem to the Rescue

If our requirement is that when we modify the value of SLAExpirationDate__c another PageBlock is refreshed, we then need to move our ActionRegion such that is it the direct parent of that InputField AND we need to add an ActionSupport. Our derived code might be,

<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">

          <apex:pageBlockSection>

              <apex:inputField value="{!Account.name}" />
              <apex:actionRegion>
                  <apex:inputField value="{!Account.SLAExpirationDate__c}">
                      <apex:actionsupport event="onchange" rerender="TheSection"/>
                  </apex:inputField>
              </apex:actionRegion>
              <apex:outputField value="{!Account.rating}" />

          </apex:pageBlockSection>

          <apex:pageBlockSection id="TheSection" title="Another Section">

              <!-- More code here -->

          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>

And our page looks quite neat, but is missing the field label,

A missing label doesn't seem like much to a developer, but it means the world to users.

This supports our theory that PageBlockSections only have complete support for Input/OutputFields, but that doesn’t help us much. Digging through the documentation a bit we realise that PageBlockSectionItem might be another fully-supported child element of PageBlockSection, and that our theory might need to be amended. We see that this standard component supports two child elements, one of which is a label, the other being the input or output area, and we modify our code thusly,


<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">

          <apex:pageBlockSection>

              <apex:inputField value="{!Account.name}" />

              <apex:pageBlockSectionItem>
                  <apex:outputLabel value="Example Label"/>
                  <apex:actionRegion>
                      <apex:inputField value="{!Account.SLAExpirationDate__c}">
                          <apex:actionsupport event="onchange" rerender="TheSection"/>
                      </apex:inputField>
                  </apex:actionRegion>
              </apex:pageBlockSectionItem>

              <apex:outputField value="{!Account.rating}" />

          </apex:pageBlockSection>

          <apex:pageBlockSection id="TheSection" title="Another Section">

              <!-- More code here -->

          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>

Which gives us a user friendly, well-formatted page,

Obviously we need to now expand our theory to say, “In order to support the expected formatting, PageBlockSections must contain only Input/OutputFields and/or PageBlockSectionItems”.

But I can’t use Input/OutputFields as my Variables are Class-bound

This theory is complete, but how do we achieve this type of formatting when our fields aren’t bound to an Object i.e. what if my fields are bound to variables in a class? It’s a good question, and is supported by our theory statement with a single caveat, you cannot use InputFields with fields not bound to objects so your only option is to use PageBlockSectionItems,

public with sharing class AccountExt {
    public String aString{get;set;}

    public AccountExt(ApexPages.StandardController controller) {
        Account a = (Account)controller.getSubject();
        aString = a.id; // A dummy value for demonstration
    }

}
<apex:page standardController="Account" extensions="AccountExt">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 1">
          <apex:pageBlockSection>
              <apex:inputField value="{!Account.name}" />
              <apex:inputField value="{!Account.SLAExpirationDate__c}" />
              <apex:outputField value="{!Account.rating}" />

              <!-- Input/OutputFields don't support Class variables/methods for their value attribute -->
              <apex:pageBlockSectionItem>
                  <apex:outputLabel value="Class Var Value"></apex:outputLabel>
                  <apex:outputText value="{!aString}"></apex:outputText>
              </apex:pageBlockSectionItem>

          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>


Our theory can be seen to cover all of our cases, and that makes us happy inside. There is one further topic worth expanding on, namely that of complex-labels & complex-inputs.

Complex Labels & Inputs within PageBlockSections

From time to time you might want to use two separate pieces of text in a label, or perhaps more than one input for a single field, whilst maintaining the default formatting. This can’t be done with an Input/OutputField, and it would violate the rule that states that a PageBlockSectionItem can only have two children components, so what sort of trickery could we employ to help us?

If we consider the example requirement that dictates, ‘A small help-link should appear next to certain inputs’ we realise that some input groupings are going to require 3 items (the label, the input and a link). We sit back, have a think and the solution presents itself, “We can group components within OutputPanels, and as long as we only have two OutputPanels within the PageBlockSectionItem – the first grouping being the ‘label’, and the second grouping being the ‘input’ – we will not violate the constraint on PageBlockSectionItems”. A contrived page sample,

<apex:page standardController="Account">
    <apex:sectionHeader title="Examples"/>
    <apex:form>
      <apex:pageBlock title="Example 2">
          <apex:pageBlockSection>

              <apex:pageBlockSectionItem>

                  <apex:outputLabel value="{!$ObjectType.Account.fields.name.label}"></apex:outputLabel>
                  <apex:outputPanel>
                      <apex:inputText value="{!Account.name}"></apex:inputText>
                      <apex:outputLink value="#">?</apex:outputLink>
                  </apex:outputPanel>

              </apex:pageBlockSectionItem>

          </apex:pageBlockSection>
      </apex:pageBlock>
    </apex:form>
</apex:page>

With the resulting formatting,

Even though we're using fields bound to the Account object, we need to use our custom structure to create a richer UI.

In Summary

We’ve discovered the rule that governs when formatting is correctly applied to children of the PageBlockSection element, and we’ve learnt a few tricks we can employ when our UI requirements begin to get complicated. Now all we need to do is take these atomic examples and apply them to the real world. Good luck.

About these ads

4 Responses

Subscribe to comments with RSS.

  1. Thanks for this! I’ve been using Visualforce for ages and did not know that you could bundle more than one child component into through use of output panels.

    Andy Rouse

    April 26, 2010 at 10:39 am

  2. Brilliant, I just spent longer than I want to think about struggling with this exact issue. Thanks for posting!

    Anna

    May 24, 2012 at 11:00 pm

  3. Thank you very much!!!

    Saludos desde México!!!

    Mario

    August 17, 2012 at 5:26 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 2,096 other followers

%d bloggers like this: