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,
[code language=”xml”]
<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>
[/code]
Which yields the following UI,
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,
[code language=”xml”]
<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>
[/code]
You end up with a partially formatted page that looks something like this,
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,
[code language=”xml”]
<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>
[/code]
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,
[code language=”xml”]
<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>
[/code]
And our page looks quite neat, but is missing the field label,
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,
[code language=”xml”]
<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>
[/code]
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,
[code language=”java”]
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
}
}
[/code]
[code language=”xml”]
<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>
[/code]
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,
[code language=”xml”]
<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>
[/code]
With the resulting formatting,
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.
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.
Glad I could help.
Brilliant, I just spent longer than I want to think about struggling with this exact issue. Thanks for posting!
Thank you very much!!!
Saludos desde México!!!