Calling Apex from LWC – Real Examples

Lightning Web Components can call Apex methods from JavaScript for business logic, data creation, updates, and complex queries.

1. Calling Apex with @wire

Use @wire for read-only Apex calls and reactive data fetching.


// accountList.js
import { LightningElement, wire, track } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';

export default class AccountList extends LightningElement {
    @track accounts;
    @track error;

    @wire(getAccounts)
    wiredAccounts({ error, data }) {
        if (data) {
            this.accounts = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.accounts = undefined;
        }
    }
}
  

Apex Class


public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List getAccounts() {
        return [SELECT Id, Name, Phone, Industry FROM Account LIMIT 50];
    }
}
  

2. Imperative Call for Create/Update

Use imperative Apex when you need actions triggered by user interaction.


// accountForm.js
import { LightningElement, track } from 'lwc';
import saveAccount from '@salesforce/apex/AccountController.saveAccount';

export default class AccountForm extends LightningElement {
    @track accountName = '';
    @track isLoading = false;
    @track error;

    handleNameChange(event) {
        this.accountName = event.target.value;
    }

    async handleSave() {
        this.isLoading = true;
        this.error = undefined;
        try {
            await saveAccount({ accountName: this.accountName });
            this.accountName = '';
        } catch (error) {
            this.error = error.body ? error.body.message : error.message;
        } finally {
            this.isLoading = false;
        }
    }
}
  

Apex Class


public with sharing class AccountController {
    @AuraEnabled
    public static Account saveAccount(String accountName) {
        Account acc = new Account(Name = accountName);
        insert acc;
        return acc;
    }
}
  

3. Passing Parameters to Apex

Pass values from the client to Apex using object literals.


// accountDetails.js
import { LightningElement, track } from 'lwc';
import updateAccount from '@salesforce/apex/AccountController.updateAccount';

export default class AccountDetails extends LightningElement {
    @track account = { id: '', name: '', phone: '' };
    @track error;

    async handleUpdate() {
        try {
            await updateAccount({ 
                accountId: this.account.id,
                accountName: this.account.name,
                accountPhone: this.account.phone
            });
        } catch (error) {
            this.error = error.body ? error.body.message : error.message;
        }
    }
}
  

Apex Class


public with sharing class AccountController {
    @AuraEnabled
    public static void updateAccount(Id accountId, String accountName, String accountPhone) {
        Account acc = [SELECT Id FROM Account WHERE Id = :accountId LIMIT 1];
        acc.Name = accountName;
        acc.Phone = accountPhone;
        update acc;
    }
}
  

4. Using refreshApex()

When Apex data changes, use refreshApex to reload wired data.


import { LightningElement, wire, track } from 'lwc';
import { refreshApex } from '@salesforce/apex';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
import deleteAccount from '@salesforce/apex/AccountController.deleteAccount';

export default class AccountManager extends LightningElement {
    @track accounts;
    @track error;
    wiredAccountsResult;

    @wire(getAccounts)
    wiredAccounts(result) {
        this.wiredAccountsResult = result;
        if (result.data) {
            this.accounts = result.data;
            this.error = undefined;
        } else if (result.error) {
            this.error = result.error;
        }
    }

    async handleDelete(event) {
        const accountId = event.target.dataset.id;
        try {
            await deleteAccount({ accountId });
            await refreshApex(this.wiredAccountsResult);
        } catch (error) {
            this.error = error.body ? error.body.message : error.message;
        }
    }
}
  

5. Error Handling Example

Always wrap imperative Apex calls with try/catch, and show user-friendly messages.


try {
    await saveAccount({ accountName: this.accountName });
} catch (error) {
    this.showErrorToast(error);
}
  

Key Takeaways