Fun in Visualforce with Dependent Select Lists

One of my background tasks right now is writing an app for Force.com Labs, a collection of free applications built by Salesforce.com employees. My app will use the Endicia Label Server API to create mailing labels, part of the UI employing a pair of selectLists allowing the user to set the label type and label size. All very straightforward, but there is a dependency between the two lists – there are different sets of label sizes for different label types, so, when the user changes the label type, the content of the label size selectList needs to change accordingly.

After a bit of headscratching and documentation reading, I came up with what I think is a nice, simple, concise solution.

My Visualforce page has a form including an actionFunction and the two selectLists:

<apex:form >
    <apex:actionFunction name="updateLabelSize" rerender="chooseLabelSize"/>
    <apex:pageBlock title="Mailing Label">
        <apex:pageBlockButtons >
            <apex:commandButton action="{!makePostageLabel}" value="Make Label" id="make_label" /> 
        </apex:pageBlockButtons> 
        <apex:pageBlockSection title="Mailing Data" columns="2"> 
            <apex:pageBlockSectionItem > 
                <apex:outputLabel value="Label Type" for="chooseLabelType"/> 
                <apex:selectList id="chooseLabelType" value="{!labelType}" size="1" onchange="updateLabelSize();"> 
                    <apex:selectOption itemValue="Default" itemLabel="Create label based on mail class" /> 
                    <apex:selectOption itemValue="CertifiedMail" itemLabel="Certified Mail" /> 
                    <apex:selectOption itemValue="DestinationConfirm" itemLabel="PLANET Code label using Destination Confirm service" /> 
                    <apex:selectOption itemValue="Domestic" itemLabel="Domestic" /> 
                    <apex:selectOption itemValue="International" itemLabel="International" /> 
                </apex:selectList> 
            </apex:pageBlockSectionItem> 
            <apex:pageBlockSectionItem > 
                <apex:outputLabel value="Label Size" for="chooseLabelSize"/> 
                <apex:selectList id="chooseLabelSize" value="{!labelSize}" size="1"> 
                    <apex:selectOptions value="{!labelSizes}"/> 
                </apex:selectList> 
            </apex:pageBlockSectionItem>
            ...

The label size list is populated by a controller function, getLabelSizes(). This returns the appropriate list of label sizes based on the value of the labelType variable:

public List<SelectOption> getLabelSizes() {
    List<SelectOption> options = new List<SelectOption>();
    if (labelType.equals('DestinationConfirm')) {
        options.add(new SelectOption('7X3','7" W × 3" H'));
        options.add(new SelectOption('6X4','6" W × 4" H'));
        options.add(new SelectOption('Dymo30384', 'DYMO #30384 2-part internet label (2.25” × 7.5”)'));
        options.add(new SelectOption('EnvelopeSize10','#10 Envelope'));
        options.add(new SelectOption('Mailer7x5','7" W × 5" H'));
    } else if (labelType.equals('CertifiedMail')) {
        options.add(new SelectOption('4X6','4" W × 6" H'));
        options.add(new SelectOption('7X4','7" W × 4" H'));
        options.add(new SelectOption('8X3','8" W × 3" H'));
        options.add(new SelectOption('Booklet','9" W × 6" H envelope'));
        options.add(new SelectOption('EnvelopeSize10','#10 Envelope'));
    } else {
        options.add(new SelectOption('4X6','4" W × 6" H'));
        options.add(new SelectOption('4X5','4" W × 5" H'));
        options.add(new SelectOption('4X4.5','4" W × 4.5'));
        options.add(new SelectOption('DocTab','4" W × 6.75" H, Eltron Doc-Tab'));
        options.add(new SelectOption('6X4','6" W × 4" H'));
    }
    return options;
}

For now, I have those lists of label sizes in the code. I’ll move them out of there at some point in the future, populating options from the database. [UPDATE – Paul Eaklor correctly points out in the comments that a round-trip to the server is overkill for such a simple dependency. Watch for more samples in the future showing how to update simple dependencies on the client-side, and a more complex scenario that does justify the round-trip.]

Looking back at the Visualforce page now, the label type selectList has onchange set to a JavaScript function, updateLabelSize(), which is defined as an actionFunction.

As you might know, actionFunctions are often used for invoking controller action methods, but you might not know that you don’t need to call an action method – you can quite legally omit the action attribute. Here I’ve done just that, but set the rerender attribute to chooseLabelSize. Now, when the user changes the selection in the label type selectList, updateLabelSize will be invoked, which will cause the label size selectList to be rerendered with the appropriate set of sizes, since labelType is bound to the label type selectList.

A nice bit of Ajax UI work, without having to actually write any JavaScript 🙂

Published
January 21, 2011
Topics:

Leave your comments...

Fun in Visualforce with Dependent Select Lists