value not showing binding to the custom controller property

apexcustom-controllervisualforce

I am trying to achieve email-checking in a form. When the user types in an email address they can click the "Check email" button – which calls the ValidateEmail method in the custom controller (it does successfully) but my system.debug line in the method ALWAYS shows emailid to be null 🙁 When I hardcode an emailid value the SOQL query works fine, and redirects the user to the contact's record page.

Could someone please provide insight to why the apex:inputText element is not binding to the public emailid property I have defined in the custom controller?

Visualforce page code:

<apex:page controller="EnquiryForm2Controller" lightningStylesheets="true">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>    
    <apex:form id="theForm">
            <apex:pageBlockSection title="Contact Details" >
                <apex:inputField value="{!Applicant.FirstName}" required="true"/>
                <apex:inputField value="{!Applicant.LastName}" required="true"/>
                <apex:inputText value="{!emailid}" required="true" />                  
                <apex:commandButton action="{!ValidateEmail}" value="Check email" reRender="theForm" immediate="true"> 
                </apex:commandButton>                    
            </apex:pageBlockSection>
    </apex:form>
</apex:page>

Custom Controller code:


public with sharing class EnquiryForm2Controller {
    public Contact Applicant { get;set; }
    public String emailid {get;set;}
    

    
    
    public EnquiryForm2Controller() {
        Applicant = new Contact();       
    }
    
    public PageReference ValidateEmail(){
        System.debug('Just entered ValidateEmail');
        System.debug('emailid: ' + emailid);
        List<Contact> contactList = [SELECT Email FROM Contact WHERE Email = :emailid];

            if(contactList.size() == 1){
                System.debug('There is a match'); 
                System.debug(contactList[0].Id);
                
        String host = System.URL.getSalesforceBaseURL().toExternalForm();
        String newurl = host + '/lightning/r/Contact/' + contactList[0].Id + '/view';
        PageReference newPage = new PageReference(newurl);
        newPage.setRedirect(true);
        return newpage;
                //redirect to contact page
            }
      return null
}

Best Answer

Put your button and input field in an apex:actionRegion, and it'll allow you to make the partial update as you like:

<apex:actionRegion renderRegionOnly="false">
  <apex:inputText value="{!emailid}" required="true" />                  
  <apex:commandButton action="{!ValidateEmail}" value="Check email" reRender="theForm" />
</apex:actionRegion>

Action regions restrict the validation to just the contained fields, which is perfect for what you're trying to accomplish.