Apex ActionFunction Tag in Visualforce | SalesforceTutorial

Written by Prasanth Kumar Published on Updated on

Apex ActionFunction Tag in Visualforce | SalesforceTutorial

The <apex:actionFunction> tag enables JavaScript functions to call Apex controller methods through AJAX requests in Visualforce pages. This component bridges client-side JavaScript with server-side Apex logic, allowing dynamic page updates without full page refreshes.

What is Apex ActionFunction Tag?

The apex actionFunction tag defines JavaScript functions that can invoke Apex controller methods from client-side code. When called, it sends an AJAX request to the server, executes the specified Apex method, and optionally re-renders page components with updated data.

Key characteristics of <apex:actionFunction>:

  • Must be a child component of <apex:form>
  • Creates a JavaScript function with the specified name
  • Supports parameters to pass data from JavaScript to Apex
  • Can re-render specific page components after execution
  • Handles AJAX communication automatically

ActionFunction Tag Syntax and Attributes

Basic syntax structure:

<apex:actionFunction name="functionName" action="{!controllerMethod}" reRender="componentId" />

Essential attributes:

Attribute Required Description
name Yes JavaScript function name to create
action Yes Apex controller method to invoke
reRender No Component IDs to refresh after execution
immediate No Skip validation when true (default: false)
timeout No Request timeout in milliseconds
status No ID of actionStatus component to show progress
oncomplete No JavaScript to execute after completion
onbeforedomupdate No JavaScript to execute before DOM update

ActionFunction Placement Restrictions

Since API version 23.0, <apex:actionFunction> cannot be placed inside iteration components such as:

  • <apex:pageBlockTable>
  • <apex:repeat>
  • <apex:dataTable>
  • <apex:dataList>

This restriction prevents JavaScript function name conflicts when multiple iterations would create functions with identical names. Place actionFunction outside iteration components and pass parameters to identify specific records.

Complete Lead Form Example

This example demonstrates apex actionFunction integration with JavaScript validation and Apex controller methods. The form creates Lead records with client-side validation before server submission.

Visualforce Page Implementation

<apex:page controller="InsertLeadController" showHeader="false">

<script type="text/javascript">
function validateAndSubmit() {
    var lastName = document.getElementById('{!$Component.leadForm.leadBlock.lastNameField}').value;
    var company = document.getElementById('{!$Component.leadForm.leadBlock.companyField}').value;
    
    if(lastName === '' || company === '') {
        alert('Last Name and Company are required fields');
        return false;
    }
    
    // Call apex actionFunction
    submitLeadRecord();
    return true;
}

function handleSubmitComplete(result) {
    if(result.success) {
        alert('Lead has been created successfully');
        clearForm();
    } else {
        alert('Error creating lead: ' + result.message);
    }
}

function clearForm() {
    document.getElementById('{!$Component.leadForm.leadBlock.firstNameField}').value = '';
    document.getElementById('{!$Component.leadForm.leadBlock.lastNameField}').value = '';
    document.getElementById('{!$Component.leadForm.leadBlock.companyField}').value = '';
    document.getElementById('{!$Component.leadForm.leadBlock.mobileField}').value = '';
}
</script>
    
<apex:form id="leadForm">
    <apex:actionFunction name="submitLeadRecord" 
                        action="{!submitLead}" 
                        reRender="leadBlock,messages" 
                        oncomplete="handleSubmitComplete({!submitResult})" />
    
    <apex:pageMessages id="messages" />
    
    <apex:pageBlock title="Lead Registration Form" id="leadBlock">
        <apex:pageBlockSection columns="1">
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="First Name" />
                <apex:inputText value="{!lead.FirstName}" id="firstNameField" />
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Last Name" />
                <apex:inputText value="{!lead.LastName}" id="lastNameField" required="true" />
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Company" />
                <apex:inputText value="{!lead.Company}" id="companyField" required="true" />
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Mobile Phone" />
                <apex:inputText value="{!lead.MobilePhone}" id="mobileField" />
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Lead Status" />
                <apex:selectList value="{!lead.Status}" size="1">
                    <apex:selectOptions value="{!statusOptions}" />
                </apex:selectList>
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>
        
        <apex:pageBlockButtons>
            <apex:commandButton value="Create Lead" onclick="return validateAndSubmit();" />
            <apex:commandButton value="Clear" onclick="clearForm(); return false;" />
        </apex:pageBlockButtons>
    </apex:pageBlock>
</apex:form>
</apex:page>

Enhanced Apex Controller

public class InsertLeadController {
    public Lead lead { get; set; }
    public String submitResult { get; set; }
    
    public InsertLeadController() {
        lead = new Lead();
        // Set default status
        lead.Status = 'Open - Not Contacted';
    }
    
    public List<SelectOption> getStatusOptions() {
        List<SelectOption> options = new List<SelectOption>();
        
        // Get picklist values from Lead.Status field
        Schema.DescribeFieldResult fieldResult = Lead.Status.getDescribe();
        List<Schema.PicklistEntry> picklistValues = fieldResult.getPicklistValues();
        
        for(Schema.PicklistEntry entry : picklistValues) {
            if(entry.isActive()) {
                options.add(new SelectOption(entry.getValue(), entry.getLabel()));
            }
        }
        
        return options;
    }
    
    public PageReference submitLead() {
        try {
            // Validate required fields
            if(String.isBlank(lead.LastName)) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Last Name is required'));
                submitResult = '{"success": false, "message": "Last Name is required"}';
                return null;
            }
            
            if(String.isBlank(lead.Company)) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Company is required'));
                submitResult = '{"success": false, "message": "Company is required"}';
                return null;
            }
            
            // Insert lead record
            insert lead;
            
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.CONFIRM, 'Lead created successfully'));
            submitResult = '{"success": true, "message": "Lead created with ID: ' + lead.Id + '"}';
            
            // Reset for next entry
            lead = new Lead();
            lead.Status = 'Open - Not Contacted';
            
        } catch(DmlException e) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Error creating lead: ' + e.getMessage()));
            submitResult = '{"success": false, "message": "' + e.getMessage() + '"}';
        }
        
        return null;
    }
}

ActionFunction with Parameters

Pass data from JavaScript to Apex methods using <apex:param> components:

<apex:actionFunction name="updateRecord" action="{!updateMethod}">
    <apex:param name="recordId" value="" assignTo="{!selectedId}" />
    <apex:param name="fieldValue" value="" assignTo="{!newValue}" />
</apex:actionFunction>

<script>
function callUpdate(id, value) {
    updateRecord(id, value);
}
</script>

Error Handling and Best Practices

JavaScript Error Handling

function safeActionCall() {
    try {
        if(typeof myActionFunction === 'function') {
            myActionFunction();
        } else {
            console.error('ActionFunction not available');
        }
    } catch(e) {
        console.error('ActionFunction error:', e);
        alert('An error occurred. Please try again.');
    }
}

Apex Exception Handling

public PageReference processData() {
    try {
        // Business logic here
        Database.SaveResult result = Database.insert(records, false);
        
        if(!result.isSuccess()) {
            for(Database.Error error : result.getErrors()) {
                ApexPages.addMessage(new ApexPages.Message(
                    ApexPages.Severity.ERROR, 
                    error.getMessage()
                ));
            }
        }
    } catch(Exception e) {
        ApexPages.addMessage(new ApexPages.Message(
            ApexPages.Severity.ERROR, 
            'Unexpected error: ' + e.getMessage()
        ));
        System.debug('ActionFunction error: ' + e.getStackTraceString());
    }
    
    return null;
}

Performance Considerations

  • Governor Limits: ActionFunction calls count toward Apex execution limits
  • View State: Minimize view state size by using transient variables for temporary data
  • Re-rendering: Only re-render necessary components to reduce response time
  • Timeout: Set appropriate timeout values for long-running operations
  • Bulk Operations: Avoid multiple actionFunction calls in loops; batch operations instead

ActionFunction vs Alternatives

Component Use Case JavaScript Integration Page Refresh
actionFunction JavaScript-triggered Apex calls Full integration Partial (reRender)
commandButton Form submissions Limited (onclick) Full page
commandLink Navigation with actions Limited (onclick) Full page
actionSupport Event-driven actions Event-based Partial (reRender)
remoteAction Direct JavaScript-to-Apex Full control None

Migration to Lightning Web Components

For new development, consider Lightning Web Components (LWC) instead of Visualforce with actionFunction. LWC provides:

  • Modern JavaScript framework (ES6+)
  • Better performance and security
  • Native Apex method calls via @wire and imperative calls
  • Component-based architecture
  • Mobile-responsive by default

Example LWC equivalent:

// JavaScript Controller
import { LightningElement, track } from 'lwc';
import submitLead from '@salesforce/apex/InsertLeadController.submitLead';

export default class LeadForm extends LightningElement {
    @track leadData = {};
    
    handleSubmit() {
        submitLead({ leadRecord: this.leadData })
            .then(result => {
                // Handle success
                this.showToast('Success', 'Lead created', 'success');
            })
            .catch(error => {
                // Handle error
                this.showToast('Error', error.body.message, 'error');
            });
    }
}

Frequently Asked Questions

Can apex actionFunction be used outside of apex:form?

No, apex:actionFunction must be a child component of apex:form. The form component provides the necessary context for AJAX requests and parameter binding.

Why can’t I place actionFunction inside iteration components?

Since API version 23.0, actionFunction cannot be placed inside iteration components like apex:repeat or apex:pageBlockTable because it would create multiple JavaScript functions with the same name, causing conflicts. Place the actionFunction outside the iteration and use parameters to pass record-specific data.

How do I pass multiple parameters to apex actionFunction?

Use multiple apex:param components within the actionFunction tag. Each param can bind to a controller property using the assignTo attribute. Call the JavaScript function with the same number of parameters in the same order.

What happens if the apex actionFunction call fails?

Failed actionFunction calls trigger the onerror JavaScript callback if specified. Server-side exceptions are caught by the Apex controller’s try-catch blocks. Use ApexPages.addMessage() to display user-friendly error messages and check ApexPages.hasMessages() in JavaScript callbacks.

Can I call multiple apex methods from one actionFunction?

No, each actionFunction can only call one Apex method specified in the action attribute. To call multiple methods, either create separate actionFunction components or call multiple methods from within a single Apex method.

How do I handle long-running operations with actionFunction?

Use the timeout attribute to set a longer timeout value, implement apex:actionStatus to show progress indicators, and consider breaking long operations into smaller chunks. For very long operations, use @future methods or Queueable Apex instead.