function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
pjcocopjcoco 

Populating picklist from AJAX response

I have this simple VF page with a lookup field for accounts, and a picklist for contacts,  the picklist should be empty until an account has been filled in. Whenever the account field changes, an AJAX call should be made to the server and the picklist should be populated with the results

 

I was following this tutorial:

http://wiki.developerforce.com/index.php/Extended_Functionality_of_Visualforce_-_Part_2

 

but at this time I can't seem to get my picklist populated. What is wrong with my code?

 

Objects:

 

Custom Object Communication, with master Object Account.
In communication I have a master-detail relation to Account, and a lookup relation to Contact

 

 

VF Page:

 

<apex:page standardController="Communication__c" extensions="CommunicationController" standardStylesheets="false">
<apex:form >
<apex:pageBlock title="Communication">
<apex:messages />
<apex:pageBlockSection columns="1">
<apex:pageblockSectionItem >
<apex:outputLabel value="Account:" />
<apex:inputField value="{!c.Account__c}">
    <apex:actionSupport event="onchange" rerender="contacts"/>
</apex:inputField>
</apex:pageblockSectionItem>
<apex:pageblockSectionItem >
<apex:outputLabel value="Contact:" />
<apex:selectList value="{!contact}" multiselect="false" size="1" id="contacts">
       <apex:selectOptions value="{!contacts}" />
</apex:selectList>
</apex:pageblockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>    
</apex:page>

 

Apex Class:
public class CommunicationController{
    public Account account {get;set;}
    public Communication__c c{get;set;}
    public String contact{get;set;}
  
    public CommunicationController(ApexPages.Standardcontroller controller){
        c = new Communication__c();
        cType = '';
        summary='';
        file = new ContentVersion();        
    }

    public List<SelectOption> getContacts(){
        List<SelectOption> optionList = new List<SelectOption>();
        optionList.add(new SelectOption('', '- None -'));
        for(contact co : [SELECT id, name FROM contact WHERE accountid =  :c.Account__c])
        {
            optionList.add(new SelectOption(co.id,co.name));
        }
        return optionList;
    }
}

 

Thanks in advance

 

Best Answer chosen by Admin (Salesforce Developers) 
bob_buzzardbob_buzzard

Yes - you can use apex:actionregion components - this effectively breaks up the form and only submits back the inputs that you are interested in for the ajax call.  Thus you'd surround your account inputfield in an actionregion and only that would go back to the controller to generate the selectlist.

All Answers

bob_buzzardbob_buzzard

You are backing your input field with the account from the communication object in the page:

 

 

<apex:inputField value="{!c.Account__c}">
    <apex:actionSupport event="onchange" rerender="contacts"/>
</apex:inputField>

 

 

but in the controller, you check if the account property is null before retrieving the contacts:

 

 

   if(account != null){
            for(contact co : [SELECT id, name FROM contact WHERE accountid =  :c.Account__c])
            {
                optionList.add(new SelectOption(co.id,co.name));
            }
        }

 

Change this to use the account from the communication record and it should work:

 

 

   if(c.account__c != null){
            for(contact co : [SELECT id, name FROM contact WHERE accountid =  :c.Account__c])
            {
                optionList.add(new SelectOption(co.id,co.name));
            }
        }

 

 

 

 

pjcocopjcoco

hmm, that seems to be a bug that slipped in there, however, this doesn't seem to fix the problem.

 

I edited my original message to show the updated code

bob_buzzardbob_buzzard

That's strange.  It fixed it in my dev org.  Here's the code that worked for me - looks the same as yours but maybe there's a subtle difference:

 

Controller:

 

 

public class CommunicationController{
    public Account account {get;set;}
    public Communication__c c{get;set;}
    public String contact{get;set;}
  
    public CommunicationController(ApexPages.Standardcontroller controller){
        c = new Communication__c();
    }

    public List<SelectOption> getContacts(){
        List<SelectOption> optionList = new List<SelectOption>();
        optionList.add(new SelectOption('', '- None -'));
        if(c.account__c != null){
            for(contact co : [SELECT id, name FROM contact WHERE accountid =  :c.Account__c])
            {
                optionList.add(new SelectOption(co.id,co.name));
            }
        }
        return optionList;
    }
}

 

 

Page:

 

 

<apex:page standardController="Communication__c" extensions="CommunicationController" standardStylesheets="false">
<apex:form >
<apex:pageBlock title="Communication">
<apex:messages />
<apex:pageBlockSection columns="1">
<apex:pageblockSectionItem >
<apex:outputLabel value="Account:" />
<apex:inputField value="{!c.Account__c}">
    <apex:actionSupport event="onchange" rerender="contacts"/>
</apex:inputField>
</apex:pageblockSectionItem>
<apex:pageblockSectionItem >
<apex:outputLabel value="Contact:" />
<apex:selectList value="{!contact}" multiselect="false" size="1" id="contacts">
       <apex:selectOptions value="{!contacts}" />
</apex:selectList>
</apex:pageblockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>    
</apex:page>

 

 

 

pjcocopjcoco

Hmm, when I use just the code I posted here everything works as expected. However when i add extra fields to my visualforce page, somehow it magically stops working.

 

When i check the communication between the server and my browser i see an ajax call being made, but nothing happens after that. Does the rerender fails? is there no answer from the server? i don't know.

 

I'll try a few extra things and get back to you.

 

thanks for your help though!

bob_buzzardbob_buzzard

That's odd.  I wouldn't expect additional fields to give it a problem, unless you maybe have a validation error or a required field not being populated - in those cases the error can be hidden by an ajax call.

pjcocopjcoco

I narrowed the problem down a little bit.

 

So, when I add another field to my form it stops working.

Somehow the ajax response doesn't contain the information anymore, so the rerender doesn't add anything.

 

AJAX Response without extra form fields (as you can see, the option values are in here):

 

<?xml version="1.0"?>
<html lang="en_US" xmlns="http://www.w3.org/1999/xhtml"><head><title></title><script src="/faces/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript" type="text/javascript">
</script><script src="/static/102010/js/picklist.js" type="text/javascript">
</script></head><body><div id="j_id0:j_id1:j_id12"></div><select id="j_id0:j_id1:j_id2:j_id4:j_id9:contacts" name="j_id0:j_id1:j_id2:j_id4:j_id9:contacts" size="1"><option value="">- None -</option><option value="003R000000WUQ5QIAX">Gert Deblekere</option><option value="003R000000WUQ5VIAX">Cameron Debruyne</option></select><meta name="Ajax-Update-Ids" content="j_id0:j_id1:j_id12,j_id0:j_id1:j_id2:j_id4:j_id9:contacts" /><span id="ajax-view-state">[extra unrelated info]</body></html>

 

AJAX Response with 1 extra field on my form (here the extra option values are missing from the response)

 

 

<?xml version="1.0"?>
<html lang="en_US" xmlns="http://www.w3.org/1999/xhtml"><head><title></title><script src="/faces/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript" type="text/javascript">
</script><script src="/static/102010/js/picklist.js" type="text/javascript">
</script></head><body><div id="j_id0:j_id1:j_id15"></div><select id="j_id0:j_id1:j_id2:j_id4:j_id9:contacts" name="j_id0:j_id1:j_id2:j_id4:j_id9:contacts" size="1"><option value="">- None -</option></select><meta name="Ajax-Update-Ids" content="j_id0:j_id1:j_id15,j_id0:j_id1:j_id2:j_id4:j_id9:contacts" /><span id="ajax-view-state">[extra unrelated info]</body></html>

 

 

pjcocopjcoco
For reference, here is the exact Vforce page and APEX class I use (this time with extra fields):
Visual Force Page
<apex:page standardController="Communication__c" extensions="CommunicationTestController" standardStylesheets="false">
<apex:form >
<apex:pageBlock title="Communication">
<apex:messages />
<apex:pageBlockSection columns="1">
<apex:pageblockSectionItem >
<apex:outputLabel value="Account:" />
<apex:inputField value="{!c.Account__c}">
    <apex:actionSupport event="onchange" rerender="contacts"/>
</apex:inputField>
</apex:pageblockSectionItem>
<apex:pageblockSectionItem >
<apex:outputLabel value="Contact:" />
<apex:selectList value="{!contact}" multiselect="false" size="1" id="contacts">
       <apex:selectOptions value="{!contacts}" />
</apex:selectList>
</apex:pageblockSectionItem>
<apex:pageblockSectionItem >
<apex:outputLabel value="Titel:" /><apex:inputField value="{!c.Title__c}" />
</apex:pageblockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>    
</apex:page>

 

APEX Class:
public class CommunicationTestController{
    public Account account {get;set;}
    public Communication__c c{get;set;}
    public String contact{get;set;}
  
    public CommunicationTestController(ApexPages.Standardcontroller controller){
        c = new Communication__c();
    }
    public List<SelectOption> getContacts(){
        List<SelectOption> optionList = new List<SelectOption>();
        optionList.add(new SelectOption('', '- None -'));
        for(contact co : [SELECT id, name FROM contact WHERE accountid = :c.Account__c])
        {
            optionList.add(new SelectOption(co.id,co.name));
        }
        return optionList;
    }
}
pjcocopjcoco

Hmmm, It looks like the requirement is indeed stopping the ajax call.

 

Because Title is a required field, when I fill something in in the field before forcing the ajax call it indeed gives me the correct response.

 

Is there any way around this problem?

bob_buzzardbob_buzzard

Yes - you can use apex:actionregion components - this effectively breaks up the form and only submits back the inputs that you are interested in for the ajax call.  Thus you'd surround your account inputfield in an actionregion and only that would go back to the controller to generate the selectlist.

This was selected as the best answer
pjcocopjcoco

cheers, this worked like a charm!