[SalesForce] Is it possible to test list size from a VisualForce page

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?

Best Answer

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}">
Related Topic