Find your content:

Search form

You are here

Splitting up an apex:repeat alphabetically

 
Share

I'm creating a custom Visualforce page and have a list of contacts to make a "list view" kind of table. Perfect for an apex:repeat I thought.

One of the requirements, however, is to split up the Contacts depending on the letter their surname begins with. So you might have:

A

Abbas, Ahmed
Adamson, Neil

B

Ball, Alan

E

Edgar, Dean

I realize this will complicate the apex:repeat, but I'm not sure how to best solve it. The only thing I can think of at the moment is to create 26 Lists with names like List contactsA, List contactsB etc. and use an apex:repeat for each of them, but that's pretty grim and I imagine the governor limits would be lurking around some dark corner. What's the best solution?


Attribution to: George S.

Possible Suggestion/Solution #1

UPDATE - I have tested this now, my original answer was almost correct but not quiet right, I made the wrong suggestion that a variable could be passed to an apex:repeat. This has been remedied by passing back the Map rather than getting the controller to extract the list from the map.

I think your best bet here is to create a custom controller that loads all your contacts into Lists that are then stored in a Map by letter.

You should be able to overcome the need for 26 apex:repeats by using a nested apex:repeat. This page may be of help:

http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_repeat.htm

VF Page:

<apex:page controller="myController">
<apex:pageBlock >
<apex:repeat value="{!alphabet}" var="letter">
    <apex:pageBlockSection title="{!letter}">
        <apex:repeat value="{!alphaMap[letter]}" var="con">
            <apex:outputText value="{!con.LastName}" />
            <apex:outputText value="{!con.FirstName}" />
        </apex:repeat>
    </apex:pageBlockSection>
</apex:repeat>
</apex:pageBlock>
</apex:page>

Controller:

public with sharing class myController
    {

    public Map<String,List<Contact>> alphaConList = new Map<String,List<Contact>>();
    public String letterToGet{ get; set; }

    public myController() {
        List<Contact> cons = [SELECT Id, FirstName, LastName FROM Contact];
        letterToGet = '';

        for(Contact con: cons){
            String letter = '';
            letter = con.LastName; // Grab the lastname
            letter = letter.toUpperCase(); //Make upper case, you could always use lowercase
            letter = letter.substring(0,1); //Take only the first character
            List<Contact> conlist = new List<Contact>();

            if (alphaConList.containsKey(letter))
            {
                conlist =  alphaConList.get(letter); // return a list of Contacts for the given letter i.e. 'A'
            }

            conlist.add(con);

            alphaConList.put(letter, conlist); //Add the contact to the list
        }
    }

    public Map<String,List<Contact>> getAlphaMap()
    {
        return alphaConList;
    }

    public List<String> getAlphabet(){
        List<String> alpha = new List<String>(alphaConList.keySet());
        return alpha;
    }
}

Attribution to: Jon Hazan

Possible Suggestion/Solution #2

I like Jon's approach, but if you're looking for simpler VF markup (so you don't need 26 repeats) you can try a list of lists of contact records. The code below isn't my prettiest, but the main list will contain lists of contacts grouped by the first letter of their last name.

Controller:

public List<List<Contact>> getAlphaContacts() {
    List<List<Contact>> alphaContacts = new List<List<Contact>>();
    Contact[] cons = [select id, firstname, lastname from contact
                         order by lastname asc, firstname asc];
    if ( cons != null && cons.size() > 0 ) {
        String currentLetter = 'anyLetter';
        List<Contact> currentList = new List<Contact>();
        for ( Contact c : cons ) {
            String letter = c.lastname.substring(0,1);
            if ( currentLetter != letter ) {
                if ( currentList.size() > 0 ) {
                    alphaContacts.add(currentList);
                    currentList = new List<Contact>();
                }
                currentLetter = letter;
            }
            currentList.add(c);
        }
        if ( currentList.size() > 0 )
            alphaContacts.add(currentList);
    }
    return alphaContacts;
}

VF page:

<apex:pageBlock title="Alpha Test" >
    <apex:repeat value="{!alphaContacts}" var="alpha">
        <p style="font-weight:bold;">{!LEFT(alpha[0].lastname, 1)}</p>
        <apex:repeat value="{!alpha}" var="con">
            {!con.lastname}, {!con.firstname}<br/>
        </apex:repeat>
    </apex:repeat>
</apex:pageBlock>

This will produce something similar to:

B
Barr, Tim
Bond, James
Bond, John
Boyle, Lauren

D
D'Cruz, Liz
Davis, Josh

F
Forbes, Sean
Frank, Edna

G
Gonzalez, Rose
Green, Avi
Grey, Jane

Attribution to: JCD
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1502

My Block Status

My Block Content