Salesforce Admin Blog

Wrapper Class Example for Visualforce Page

I must admit that when I first heard about using a wrapper class in a Visualforce page I did not really grasp the concept. Reading the developer docs and reading other blogs didn’t really help either. It was only when I came across a practical use case that the concept really sunk in and I thought I would share that here for any other developers trying to make sense of the idea.

You can look up the proper technical definition of an Apex wrapper class but I think of them as a way to create a collection of multiple data types and/or records. For the purposes of this code sample, I am going to build upon an example I used earlier this year where I was trying to reduce the heap size of a Visualforce controller. In that example I was grabbing a bunch of accounts and displaying them in a related list format within a Visualforce page. In this example I am going to show you how to turn that logic into a wrapper class so that the Visualforce page displays more information than simply the account records.

Let's presume that the requirement is to add a row counter to the data rows that are displayed in the Visualforce page. Since the counter is not natively stored on the Account object we will need to add it to our record collection prior to passing the Accounts back to the Visualforce page. This is a practical example of when you would utilize a wrapper class in your code.

The wrapper will literally allow us to combine the Account records and this arbitrary counter variable together so that we can utilize both objects in the page. Using the previous code as a starting point we will only have to make some simple modifications in order to make everything work.

Let's start with the modifications to the controller for the page. Again, we are using the code from a previous example. So most of it will remain intact. The first change we will make is re-purposing the existing display_list variable. We will alter it from a list of Accounts to a list of wrapper objects, which we will call a list of accountWrappers.

Next, we will modify the getRecordsToDisplay method in order to handle populating our new list of accountWrapper objects instead of populating Accounts.

Last we will create a new accountWrapper class and method, which will handle populating our wrapper with the objects/data we need. The completely updated controller is below:

/*
    Created by: Greg Hacic
    Last Update: 1 June 2012 by Greg Hacic
    Questions?: greg@interactiveties.com
*/
public with sharing class controller_for_page {
    
    public List<accountWrapper> display_list {get; set;} //list for all Account records and a row counter
    public List<String> current_list = new List<String>(); //list for holding many record Ids
    public List<String> next_list = new List<String>(); //list for holding record Ids that are after the current records
    public List<String> previous_list = new List<String>(); //list for holding record Ids that are before the current records
    Integer list_size = 50; //number of records to display on the page
    
    //initiates the controller and displays some initial data when the page loads
    public controller_for_page() {
        Integer record_counter = 0; //counter
        for (Account a : [SELECT Id FROM Account ORDER BY Name LIMIT 10000]) { //for a bunch of accounts
            if (record_counter < list_size) { //if we have not yet reached our maximum list size
                current_list.add(a.Id); //add the Id of the record to our current list
            } else { //otherwise, we reached our list size maximum
                next_list.add(a.Id); //add the Id to our next_list
            }
            record_counter++;
        }
    }
    
    public List<accountWrapper> getRecordsToDisplay() {
        Set<String> record_ids = new Set<String>(); //set for holding distinct Ids
        Boolean records_added = record_ids.addAll(current_list); //add all the records from our current_list list
        display_list = new List<accountWrapper>(); //set the display_list object to a new accountWrapper List
        Integer counter = 1; //row counter variable
        for (Account a : [SELECT AccountNumber, Id, Name, OwnerId, Phone, Site, Type FROM Account WHERE Id in : record_ids ORDER BY Name]) { //query for the details of the records you want to display
            display_list.add(new accountWrapper(a, counter)); //add the account and counter to our list
            counter++; //increment the counter
        }
        return display_list; //return the list of full records plus their row counter
    }
	
    public class accountWrapper {
        public Account act {get; set;} //Account object
        public Integer numberOfRow {get; set;} //row counter variable
        
        public accountWrapper(Account a, Integer rowCounter) {
            this.act = a; //assign account
            this.numberOfRow = rowCounter; //assign row counter
        }
    }
	
    public Integer getCurrentSize() {
        return current_list.size(); //number of record in current_list
    }
    
    public Integer getPrevSize() {
        return previous_list.size(); //number of record in previous_list
    }
    
    public Integer getNextSize() {
        return next_list.size(); //number of record in next_list
    }

}

Now we need to modify the Visualforce page so that it will handle the list of accountWrapper records instead of Account records. The completely updated code is below:

<apex:page controller="controller_for_page" sidebar="false">
<!--
    Created by: Greg Hacic
    Last Update: 1 June 2012 by Greg Hacic
    Questions?: greg@interactiveties.com
-->
    <apex:form>
        <apex:pageBlock mode="maindetail" title="Wrapper Class: Example">
            <apex:outputPanel>{!IF( OR(prevSize > 0, currentSize > 0), prevSize + 1, 0)} to {!prevSize + currentSize} of {!prevSize + currentSize + nextSize}</apex:outputPanel>
            <apex:actionStatus>
                <apex:facet name="start">Loading...</apex:facet>
                <apex:facet name="stop">
                    <apex:pageBlockTable value="{!recordsToDisplay}" var="r">
                        <apex:column value="{!r.numberOfRow}">
                            <apex:facet name="header">#</apex:facet>
                        </apex:column>
                        <apex:column value="{!r.act.Name}"></apex:column>
                        <apex:column value="{!r.act.Site}"></apex:column>
                        <apex:column value="{!r.act.AccountNumber}"></apex:column>
                        <apex:column value="{!r.act.Phone}"></apex:column>
                        <apex:column value="{!r.act.Type}"></apex:column>
                        <apex:column value="{!r.act.OwnerId}"></apex:column>
                    </apex:pageBlockTable>
                </apex:facet>
            </apex:actionStatus>
            <apex:outputText rendered="{!IF(currentSize > 0,false,true)}" value="No Records to Display..."></apex:outputText>
        </apex:pageBlock>
    </apex:form>
</apex:page>

The most obvious alteration you will notice from the old Visualforce page and the new Visualforce page is that there is some additional dot notation in the value attribute of the apex:column tags. This is what permits the page to display either the values from the account object or the data from our row counter variable.

Feel free to review the original code sample and the new in order to fully understand the changes that were made to permit the use of a wrapper class in the logic.

As always, I appreciate you taking the time to read this post.
-greg

Share this Post