Two Visualforce Methods for Conditional Lists
Sometimes things which should be easy, and standard, don't actually exist and this can cause some level of consternation for a developer looking for them. A common requirement when displaying a list of records for instance, is to show the records should they exist, otherwise to display a message to the effect that there aren't any. This is easy enough to accomplish with Visualforce when using a custom controller or an extension, but not so with a standard controller. This does not mean, however, that it can't be done.
First up, a disclaimer (these seem to be getting somewhat common around here). The techniques explained here are unsupported by Salesforce. That is to say, the first one in particular has been highlighted to be so, while the second is a method I devised a few days ago (and have not seen elsewhere) but does come with a the 'hack' label firmly stapled onto it.
Counting Crows
Whilst trying to work out a Visualforce only method recently I thought about how I might be able to count the records in a list, remembering to my delight that you can modify the value of <apex:variable>
variables (handy for creating indices), meaning of course, counting records becomes quite trivial:
<apex:variable var="count" value="{!0}"/>
<apex:repeat value="{!Account.Contacts}" var="v">
<apex:variable var="count" value="{!count + 1}"/>
</apex:repeat>
<apex:outputText value="Found some contacts!" rendered="{!count != 0}"/>
No sooner had I discovered this method for myself, I came across a question on the Salesforce StackExchange site with an answer by Andrew Fawcett using the exact same idea, but I still wasn't entirely happy.
My major gripe with this technique was that it feels like it's inefficient, not to mention it requires an extra four lines of code per list. Having experimented for a few hours with various ideas, I can now demonstrate a more concise way (the jury is out on efficiency) to achieve this goal.
Another Way
When you output an empty list directly in a page, you simply get what looks to be an empty array, i.e. two square brackets containing absolutely nothing. Trying to simply compare against a string doesn't work since an empty array isn't a string, so rendered="{!Account.Contacts != '[]'}"
is out.
You can't cast the list to a string value using TEXT()
, which is a shame because then the solution would be simple, rendered="{!TEXT(Account.Contacts) != '[]'}";
but that's out too. Similarly, wrapping the list part in quotes to make it a string is no use as then we're just comparing the string 'Account.Contacts'
with '[]'
, and we know they're not the same.
Once again, our friend <apex:variable>
leaps into action and saves the day: in specifying its value we can put the merge expression inside some single quotes like so:
<apex:variable var="v" value="'{!Account.Contacts}'"/>
Meaning now the variable v
has the value '[]'
—single quotes included—if there are no contacts for the account. We need to compare against a string which has the same value, again including the quotes. So far my attempts at escaping quotes directly in the comparison have proven unsuccessful, but we can avoid the need to do so by using a second <apex:variable>
, thus:
<apex:variable var="v2" value="'[]'"/>
The upshot is now all we need do is perform a comparison between the two variables to decide whether or not the list has any records.
<apex:outputField value="Contacts established. Launching in T-10..." rendered="{!v != v2}"/>
A bonus is that the variable v2 above is reusable for each list, so all in we only need to add n+1 lines of markup to deal with n lists which helps keep our page source nice and tidy.