31

Consider a simple example of a VF page that shows an account, with a pageBlockTable to display contacts on the account. But if there are no contacts for the accounts, instead of an empty table we want to display a message.

VisualForce Page:

<apex:page standardController="Account" extensions="AccountHelper">

  <apex:pageBlock title="Account">
      <apex:outputField value="{!account.name}"/>
  </apex:pageBlock>
  <apex:pageBlock title="Related Contacts">
      <apex:pageBlockTable value="{!contacts}" var="ct" rendered="true">
          <apex:column value="{!ct.name}"/>
          <apex:column value="{!ct.phone}"/>
      </apex:pageBlockTable>
      <apex:pageMessage summary="Account has no contacts" severity="info" rendered="true" />
  </apex:pageBlock>
</apex:page>

AccountHelper.cls:

public with sharing class AccountHelper {
    private Account account;

    public AccountHelper(ApexPages.StandardController controller) {
        account = (Account)controller.getRecord();
    }

    public List<Contact>getContacts() {
        return [select id, name, phone from Contact where accountid=:account.id];
    }
}

Note that both the 'pageBlockTable' and the 'pageMessage' in the above example include rendered='true'. What we want of course is a test of the contacts list from the controller, like this:

<!-- doesn't work, this is apex, not a formula as required -->
<apex:pageBlockTable ... rendered="contacts.size()>0">

I can't find a formula to test the list size. Is there a simple way to test this in the VF page?

One approach is to move the test to the controller, for example:

public with sharing class AccountHelper {
    private Account account;

    public List<Contact> contacts {
        get {
            if (contacts==null) {
                contacts = [select id, name, phone from Contact where accountid=:account.id];
            }
            return contacts;
        }
        set;
    }

    public AccountHelper(ApexPages.StandardController controller) {
        account = (Account)controller.getRecord();
    }

    public boolean getHasContacts() {
        return contacts.size() > 0;
    }

}

The VF page is then updated to match, e.g., rendered="{!hasContacts}. However, the list of contacts is now being cached. In a more complex example with action methods that update the database and rerender parts of the page dynamically, changes to the account's contacts in the database will not be picked up, unless we ensure each such action method also set contacts to null to ensure a fresh query. Not onerous, but our controller extension keeps adding code for what should have been a simple in-page test.

But let's take the example one step further. Let's say that we want alter the display (add an icon, or change the background color) of each contact based on whether or not the contact has any cases in the system. The query in the controller can get cases:

contacts = [select id, name, phone, (select casenumber from cases) from Contact where accountid=:account.id];

But how can the VF Page test the cases subquery to alter the display? The only approach I know of is to create an inner wrapper class for contact, and have the Contacts getter return a List of wrapper objects; the wrapper class can the have the logic to check cases. This will work, but again, the controller is growing in complexity for what is basically a simple test - does a list have members?

42

This is just a syntax issue, your condition will work if you make a few small changes

Change

 <!-- doesn't work, this is apex, not a formula as required -->
    <apex:pageBlockTable ... rendered="contacts.size()>0">

To

 <apex:pageBlockTable ... rendered="{!contacts.size>0}">
  • the missing {! } tags are just my mistake in typing the question, but dropping the parens from contacts.size() is the magic I was missing. Further, in my extended example, {!ct.cases.size} does exactly what I need as well. Thanks! – Jason Clark Sep 29 '13 at 17:09
  • Awesome, glad to help – Chris Duncombe Sep 29 '13 at 19:00
  • 3
    You can also use '.empty' – Phil B Sep 25 '14 at 14:56
  • Good point, that will work as well. – Chris Duncombe Sep 25 '14 at 15:02
4

You can do this as:

<apex:pageBlockTable ... rendered="{!IF(contacts.size>0,'true','false')">

On visualforce page we can check conditions by:{!IF(condition,InTrueCondition,IfConditionIsFalse)}

Same as List size can be checked as:

<apex:pageBlockTable value="{!contacts}" var="ct" rendered="{!IF(contacts.size>0,'true','false')">
          <apex:column value="{!ct.name}"/>
          <apex:column value="{!ct.phone}"/>
      </apex:pageBlockTable>
      <apex:pageMessage summary="Account has no contacts" severity="info" rendered="{!IF(contacts.size>0,'false','true')" />

So by {!IF()} you can check various conditions and display results according to it. Also on VF page {!contacts.size>0} will result to true when rendered. So rendered="{!contacts.size>0}" can be used in your case.

Reference: read here

Edit: Also instead of using rendered="{!contacts.size>0}" or using {!IF()}, function {!listInstance.empty} can be used.

So in case for a empty list {!contacts.empty} will render true and {!!contacts.empty} will render false

  • 7
    IF(BooleanTest, 'true', 'false') is never needed - a boolean test by definition returns true when true and false when false. Likewise, NOT(BooleanTest) is cleaner and clearer than IF(BooleanTest, 'false', 'true'). In my case, the issue was the () on contacts.size(), which won't work in a VF formula. You currently show it both correctly and incorrectly (last example) in your answer. – Jason Clark Sep 29 '13 at 17:15
  • @JasonClark I corrected it, that was a typo mistake. Thanks! NOT(Boolean) is no doubt more cleaner. I just tried to described some of the approaches and in last line the solution. – Ashwani Sep 29 '13 at 17:20
  • 2
    I know you edited the last line to reflect, but I think what Jason is trying to say is that there is no reason ever to use a boolean condition in an IF statement in VF. Its redundant and really just adds complexity where it isn't needed. Your answer makes it seems as though it is an effective alternative, but really there is no reason to add the IF statement – Chris Duncombe Sep 29 '13 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.