1

I'm having trouble getting actionSupport to refresh a SelectOptions field on my Visualforce page.

I have two SelectOptions fields: one for a custom Site object and one for Account. The account options list field starts empty and disabled. When the user selects a Site, I want to retrieve the accounts, build the SelectOptions list, enable the field and refresh.

I am trying actionSupport but the retrieve is not working: the account options field is enabled but it remains empty.

Any thoughts on where I'm going wrong?

Here's the Visualforce page:

<apex:page controller="AttendanceEntry">

    <apex:form id="theForm">
        <apex:pageBlock title="Attendance Entry" id="theBlock">
            <apex:pageBlockSection columns="2" collapsible="false" id="filterSection">

                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="Site" />
                    <apex:selectList value="{!selectedSite}" size="1">
                        <apex:selectOptions value="{!siteValues}" />
                        <apex:actionSupport event="onchange" action="{!selectAcctList}" rerender="filterSection" />
                    </apex:selectList>
                </apex:pageBlockSectionItem>

                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="School" />
                    <apex:selectList value="{!acctValues}" size="1" disabled="{!isAcctListDisabled}">
                          <apex:selectOptions value="{!acctId}"/>
                    </apex:selectList>
                </apex:pageBlockSectionItem>

            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Here's the controller:

public with sharing class AttendanceEntry {

    public Id selectedSite { get; set; }
    public List<SelectOption> acctValues { get; set; }
    public Id acctId { get; set; }
    public Boolean isAcctListDisabled { get; set; }

    public List<SelectOption> siteValues {
        get {
            if (siteValues == null) {
                siteValues = new List<SelectOption>();
                siteValues.add(new SelectOption('', '--None--'));
                for (Site__c s : [SELECT Name FROM Site__c]) {
                    siteValues.add(new SelectOption(s.Id, s.Name));
                }
            }
            return siteValues;
        }
        set;
    }

    // Constructor
    public attendanceEntry(){
        isAcctListDisabled = true;
    }

    // Get accounts in the selected region.  Executed by actionSupport whenever site field is changed.
    public void selectAcctList() {
        acctValues = new List<SelectOption>();
        if (selectedSite != null) {
            for (Account acct : [SELECT Name FROM Account WHERE Site__c = :selectedSite]) {
                acctValues.add(new SelectOption(acct.Id, acct.Name));
            }
            isAcctListDisabled = false;
        } else {
            isAcctListDisabled = true;
        }
    }
}
  • David, you can use actionfunction (AF) that gets called onchange of site, and the AF can call your controller action and oncomplete of AF will rerender your Account picklist. – Vamsi Krishna Mar 1 '16 at 1:43
2

You've made the problem harder than it has to be as most of the work can be done directly in the getters

public with sharing class AttendanceEntry {

 public Id selectedSite { get; set; }
 public List<SelectOption> availAccts {
    get {
       availAccts = new List<SelectOption>();
       if (selectedSite != null) 
         for (Account acct : [SELECT Name FROM Account WHERE Site__c = :selectedSite]) 
            availAccts.add(new SelectOption(acct.Id, acct.Name));
       return availAccts;
    }
    private set;
 public Id selectedAcctId { get; set; }
 public Boolean isAcctListDisabled {
   get {return this.selectedSite == null;}
   private set;


// Constructor
public attendanceEntry(){}  // nothing to do here

public void selectAcctList() {} // does nothing, merely a placeholder for debugging that onchange action actually happened

and your VF page, second selectList should be (note I changed the variable names to be clearer):

<apex:pageBlockSectionItem>
  <apex:outputLabel value="School" />
    <apex:selectList value="{!selectedAcct}" size="1" disabled="{!isAcctListDisabled}">
       <apex:selectOptions value="{!availAccts}"/>
    </apex:selectList>
</apex:pageBlockSectionItem> 

so, how does this all work?

  1. When the page is initially shown, the second slectList is disabled because no site is selected
  2. When a site is chosen, the actionSupport does a POST and the pageBlockSection is rerendered
  3. Thus, the value of availAccts is fetched from its getter
  4. Thus the value of isAcctListDisabled fetched from its getter
  5. If the user changes the site, steps 2-4 are repeated

In general, the less logic you have to write between action methods updating fields that are getters to the VF page, the cleaner and easier everything is

  • thanks for the detailed response, much more elegant. Also I didn't realize I had reversed the acctValues and acctId in my original VF page, how embarrassing. – David Cheng Mar 1 '16 at 17:15
  • np -- one of the hardest things for me to realize over the years was that the VF designers had an implicit 'elegance' model in mind when it came to the controllers (but the doc isn't really good at revealing this) so developers (and I was one of them), overcomplicated the solution. – cropredy Mar 1 '16 at 17:52

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.