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
b.db.d 

update fields outside of an action region

I am having a problem with the Visualforce ajax components. 

 

I have a selectCheckboxes for which I want to dynamically populate the selected boxes as a function of two other components on the SObject. The selected items is a property on the controller, a getter. The issue is that when the ajax call is made, the fields that this property is using to calculate the items that should be selected do not seem to be set on the controller. My understanding is that they are not updated on the server side, because they are outside the action region of the ajax call. I tried adding those components to the rerender attribute, but have not seen the desired behavior. Is there a way to make sure the setters for those fields are called before the rest of the methods in question are called?

 

 

<apex:page standardController="Call_Report__c"
	extensions="CallReportExtension">
	<apex:form >
		<apex:pageBlock title="Call Report">
			<apex:messages style="color:red"/>
			<apex:pageBlockButtons >
				<apex:commandButton action="{!saveCall}" value="Save" />
				<apex:commandButton action="{!Cancel}" value="Cancel" />
			</apex:pageBlockButtons>

			<apex:pageBlockSection title="Call Details" columns="2">
				<apex:inputField value="{!call.Account__c}" id="acct"
					required="True" />
				<apex:inputField value="{!call.Contact__c}" />
				
				</apex:actionRegion>
                <apex:pageBlockSectionItem >
                    <apex:outputLabel value="               " for="blank"/>
                    <apex:outputText value="                " id="blank"/>
                </apex:pageBlockSectionItem>
				
				<br />
				<br />
			</apex:pageBlockSection>
			<apex:pageBlockSection columns="2">
				<apex:actionRegion >
					<b> <apex:pageBlockSectionItem >
						<apex:outputLabel value="Select Topic:" for="topic" />
						<apex:inputField value="{!Call_Report__c.Topic__c}" id="topic"
							required="true">
							<apex:actionSupport event="onchange" rerender="detailInput">
							</apex:actionSupport>
						</apex:inputField>
					</apex:pageBlockSectionItem> </b>
				</apex:actionRegion>
				<apex:outputPanel id="detailInput">
					<b> <apex:pageBlockSectionItem rendered="{!Call_Report__c.Topic__c=='Tickers'}">
						<apex:outputLabel value="Select Tickers: " for="tickerInput" />
						<apex:inputField value="{!Call_Report__c.Tickers__c}"
							required="{!Call_Report__c.Topic__c=='Tickers'}" id="tickerInput" />
					</apex:pageBlockSectionItem> <apex:pageBlockSectionItem rendered="{!Call_Report__c.Topic__c=='Industry'}">
						<apex:outputLabel value="Select Industry: " for="sectorInput" />
						<apex:inputField value="{!Call_Report__c.Sector__c}"
							required="{!Call_Report__c.Topic__c=='Industry'}"
							id="sectorInput" />
					</apex:pageBlockSectionItem> <apex:pageBlockSectionItem rendered="{!Call_Report__c.Topic__c=='Specific Bond'}">
						<apex:outputLabel value="Select Security:" for="bondInput" />
						<apex:inputField value="{!Call_Report__c.Security__c}"
							required="{!Call_Report__c.Topic__c=='Specific Bond'}"
							id="bondInput" />
					</apex:pageBlockSectionItem> </b>
				</apex:outputPanel>

				<apex:actionRegion >
                
					<apex:pageBlockSectionItem >
						<apex:outputLabel style="font-weight:bold;"
							value="Select Specific Employees to Notify"
							for="specificEmpsSelector" />

						<apex:inputCheckbox id="specificEmpsSelector"
							value="{!renderSpecificEmps}">
							<apex:actionSupport action="{!setFields}" event="onchange" rerender="checks,topic,detailInput,acct">
							</apex:actionSupport>
						</apex:inputCheckbox>

					</apex:pageBlockSectionItem>

				</apex:actionRegion>
				<!-- the following element is included because the controller only has access to fields on the page,
                so this saves a query in the controller.  -->
				<apex:outputText value="{!Call_Report__c.Specific_Employees__c}"
					rendered="false" />
			</apex:pageBlockSection>
			<apex:outputPanel id="checks">
			
			</br> </b>
				<apex:selectCheckboxes value="{!chosenEmployeeNames}"
					layout="pageDirection" rendered="{!renderSpecificEmps}">
					<apex:selectOptions value="{!availableEmployeeNames}" />
				</apex:selectCheckboxes>
			</apex:outputPanel>
		</apex:pageBlock>


	</apex:form>
</apex:page>

 and the controller is here:

 

 

 public static final String TICKER_TOPIC = 'Issuer';
    public static final String SECTOR_TOPIC = 'Industry';
    public static final String SPECIFIC_BOND_TOPIC = 'Specific Bond';
    public static final String DEFAULT_HOURS = '0';
    public static final String DEFAULT_MIN = '10';
    public static final String LIST_VIEW_URL = 'https://na7.salesforce.com/a0c/o';
    
    
    private Map<String, String> parameters;   
    public Contact newContact{get; private set;} 	
   // public String newContactFirst {get; set;}
   // public String newContactLast {get;set;}
    public Boolean creatingNewContact {get; set;} 
    
    public Call_Report__c call{
    	get{
        if (call == null){
            call = (Call_Report__c) controller.getRecord();
        }
        return call;
        }
     set;}
     
    private ApexPages.StandardController controller;
   
    
    public Boolean isEnabledTickers{ 
        get{
        	System.debug('~~~~~~~RENDERING TICKERS');
        	
            return parameters.get('topicSelection') == TICKER_TOPIC;
        }
    }
    
    public Boolean isEnabledSectors{
    	get {
    		System.debug('~~~~~~RENDERING SECTORS');
    		return parameters.get('topicSelection') == SECTOR_TOPIC;
    	
    	} 
    }

    public Boolean isEnabledBonds{
    	get {
    		System.debug('~~~~~~~~~~RENDERING SPECIFIC BONDS');
    		return parameters.get('topicSelection') == SPECIFIC_BOND_TOPIC;
    	}
    }
  
 
    public List<SelectOption> availableEmployeeNames {get; private set;}
    
    public ID[] chosenEmployeeNames {
    	get{
    	   EmployeeCollection interested = CallReportManager.determineInterested(call);
    	   return interested.getIDs();
        } 
    set;}
   
    
    public Map<String, Employee__c> employeeIdMap;
    public Map<String, ID> nameIDMap {
    	get{
    		Map<String, ID> m = new Map<String, ID>();
    		for (Employee__c  e: employeeIdMap.values()){
    		     m.put(e.Name, e.Id);
    			
    		}
    		return m; 
    	}
    }
    
    private void populateEmployeeMap(){
    	EmployeeCollection ec = new EmployeeSelector().whereCompanyEmailIsNotNull().whereIsCurrent().execute();
    	employeeIdMap = new Map<String, Employee__c>();
    	for (Employee__c e : ec.getList()){
    		employeeIdMap.put(e.Id, e);
    	}
    }
    
    private void getSelectOptionList(){
    	
    	//NOTE: this is convoluted and weird because Apex does not have a built-in sort
    	//for anything other than primitives, so thanks guys.
    	List<String> names = new List<String>(nameIdMap.keySet());
    	names.sort();
    	System.assert(names.size() > 0, 'employeeIDMap not populated!');
    	availableEmployeeNames = new List<SelectOption>();
    	for (String name: names){
    	   ID id = nameIdMap.get(name);
    		availableEmployeeNames.add(new SelectOption(id, name));
    	}
    	
    }
    
    private String formatSpecificEmployees(){
    	String s = call.Specific_Employees__c;
    	
    	if (s == null){
    		s= '';
    	}
    	if (chosenEmployeeNames==null){
    	   return s;
    	  
    	}
    	System.debug('~~~~~~~~~~User has selected '+ chosenEmployeeNames.size() + 'employees to notify.');
    	for (String theId : chosenEmployeeNames){
    	   //String idString = (String) o.getValue();
    	   s +=  theId + ',';
    	}
    	return s;//s.substring(0, s.lastIndexOf(','));
    }
    
    public CallReportExtension(ApexPages.StandardController c){
    	controller = c;
    	parameters = ApexPages.currentPage().getParameters();
    	chosenEmployeeNames = new List<ID>();
    	call.Call_Time__c = (call.Call_Time__c == null) ? Datetime.now(): call.Call_Time__c;
    	call.Duration_Hours__c=(call.Duration_Hours__c == null) ? CallReportExtension.DEFAULT_HOURS : call.Duration_Hours__c;
    	call.Duration_Minutes__c= (call.Duration_Minutes__c == null) ?  CallReportExtension.DEFAULT_MIN : call.Duration_Minutes__c;
    	populateEmployeeMap();
    	getSelectOptionList();
    	this.newContact = new Contact();
    	
    }
    private void addTopicToNotes(){
    	String tickerstring = 'All Tickers discussed: ';
    	String industrystring = 'Industry discussed: ';
    	String bondstring = 'Bond discussed: ';
    	if (call.Topic__c == 'Tickers'){
    		if (call.Call_Notes__c.contains(tickerstring)) {
    		 call.Call_Notes__c = call.Call_Notes__c;
    		 }else{
    		  call.Call_Notes__c = tickerstring + call.Tickers__c + '\n\n' + call.Call_Notes__c;
    		}
    	}
    	if (call.Topic__c == 'Industry'){
    		if (call.Call_Notes__c.contains(industrystring)) { 
    			call.Call_Notes__c = call.Call_Notes__c;
    		}else{
    		  call.Call_Notes__c = industrystring + call.Sector__r.name + '\n\n' + call.Call_Notes__c;
    		}
    	}
    	if (call.Topic__c == 'Specific Bond'){
    		if (call.Call_Notes__c.contains(bondstring)) {
    		  call.Call_Notes__c = call.Call_Notes__c;
    		}else{
    		  call.Call_Notes__c =  + call.Security__r.name + '\n\n' + call.Call_Notes__c;
    		}
    	}
    }
    
    public Employee__c caller{
    	get{
    		if (caller == null){
    		  ID uid = UserInfo.getUserID();
    		  EmployeeCollection emps = new EmployeeSelector().whereIsCurrent().whereUserIn(new ID[]{uid}).execute();
    		  if (emps.size() > 0){
    		  	caller = emps.getList().get(0);
    		  }else{
    		  	throw new InvalidEmployeeSetupException('There is no employee record associated with the current user-- contact HR or your IT staff to correct this configuration');
    		  }
    		}
    		return caller;
    	}
    	
    	private set;
    }
    
    
 
    public void setFields(){
    	
    }
    
    public Boolean renderSpecificEmps {
    	get; 
        set;
        
    }
    
    class InvalidEmployeeSetupException extends Exception{}
}

 

 

 

aballardaballard

ActionRegion defines a subset of the page that is to be submitted for processing.   Rerender defines a set of components that are to be updated after processing. 

 

So your action regions must be defined to include all the data that is needed for the priocessing you want to do. 

b.db.d

I gathered this from the documentation. Is there truly no way within the action region to indicate that fields outside the action region should be included? To me, this seems like a fatal flaw, when combined with the fact that the actionRegion changes the visual style of the components included within, and the fact that (at least as far as I can tell) one cannot nest actionRegions. I cannot simply wrap this page in a giant actionRegion, because that would undermine the other actionRegions on the page. 

 

Am I misunderstanding something?