How to Pass Wrapper class records to Apex in LWC

What is Wrapper Class?

Salesforce is a very powerful platform with lot of in-built features. But sometimes, In Salesforce, there are often challenges when something unique is needed – when custom development and complex data type manipulation is required. That is where we need Wrapper Class.

In layman’s term, Wrapper Class is a an object created in Apex. But technically it is an abstract data type that contains different objects or collections of objects as its members.

How to Pass Wrapper Class variable?

Lets say we want to have a LWC page with Bank Details, where users can view and edit their Bank Details. When users will edit and save these bank details, we need to send this data to Apex method to save it in the Salesforce database.

Lets say our class name is BankAccountDetailController and in that we have a wrapper class called BankDetailsWrapper

public class BankAccountDetailController {
        public class BankDetailsWrapper{
        @AuraEnabled
        public String accountNumber{get;set;}
        @AuraEnabled
        public String accountName{get;set;}
        @AuraEnabled
        public String accountId{get;set;}
      }

      @AuraEnabled
    public static void saveBankDetails(BankDetailsWrapper bankDetailsToSave) {
        Account saveAccount = new Account();
        saveAccount.BankAccountNumber__c = bankDetailsToSave.accountNumber;
        saveAccount.BankAccountName__c = bankDetailsToSave.bankAccountName;
        saveAccount.Id=bankDetailsToSave.accountId;
        update saveAccount;  
    }

    @AuraEnabled(cacheable=true)
public static BankDetailsWrapper getBankDetails(String recordId) {

    Account validAccount = [SELECT Id, Name, BankAccountNumber__c,BankAccountName__c,
                    FROM Account  
                    WHERE Id=:recordId];
    
    if(validAccount.size() >0){
        BankDetailsWrapper detailWrapper = new BankDetailsWrapper();
        
        
        detailWrapper.accountNumber = validAccount[0].BankAccountNumber__c;
        detailWrapper.bankAccountName = validAccount[0].BankAccountName__c;
        detailWrapper.accountId = validAccount[0].Id;
        return detailWrapper;
    }
    return null;
    
}
}

In this case we are using BankDetailsWrapper as our wrapper class. Name of our LWC is bankAccountDetail. We will be calling saveBankDetails method from LWC to save Bank Details and will pass BankDetailsWrapper variable with information.

<template lwc:if={bankdetail}>
                <h3 class="slds-section-title--divider"> Bank Information</h3>
                <lightning-layout horizontal-align="spread">
                    <lightning-layout-item padding="around-small">
                        <div class="header-column"> 
                            <lightning-input type="text" value={bankdetail.bankName} label="Bank Name" required></lightning-input>
                         </div>
                    </lightning-layout-item>
                    <lightning-layout-item padding="around-small">
                        <div class="header-column">
                           
                            <lightning-input type="text" value={bankdetail.bankAccountName} label="Bank Account Name" required></lightning-input>
                         </div>
                    </lightning-layout-item>
                </lightning-layout>

                <h3 class="slds-section-title--divider"> Account Details</h3>
                    <lightning-layout horizontal-align="spread">
                        <lightning-layout-item padding="around-small">
                            <div class="header-column">
                             
                                <lightning-input type="text" value={bankdetail.accountNumber} label="Account Number" required></lightning-input>
                             </div>
                        </lightning-layout-item>
                       
                    </lightning-layout>
                    <lightning-button-group>
                        <lightning-button 
                            variant="brand-outline" 
                           
                            label="Save" 
                            icon-name="utility:save"
                            onclick={saveBankDetail}>
                        </lightning-button>
                </lightning-button-group>
            </template>
<strong><span style="text-decoration: underline"><em>bankAccountDetail</em>.js
</span></strong>import { api, LightningElement,wire, track } from 'lwc';
import getBankDetails from '@salesforce/apex/BankAccountDetailController.getBankDetails';
import saveBankDetails from '@salesforce/apex/BankAccountDetailController.saveBankDetails';

export default class BankAccountDetail extends LightningElement {
@wire(getBankDetails, {
        contactId: '$recordId',
    })
    wiredBankDetails({error,data }) {
        if (data) {
            this.bankdetail = data;
        }
        else if (error) {
            this.error = error;
            this.bankdetail = undefined;
     
        }

saveBankDetail(event){
    var pass=
    {
        accountNumber:this.accountNumber,
        bankAccountName:this.bankAccountName,
        accountId:this.accountId,
    };

    saveBankDetails({bankDetailsToSave:pass})
    .then(result => {
        console.log('Data:'+ JSON.stringify(result));
        this.isSaving = false;
        this.dispatchEvent(
            new ShowToastEvent({
                title: 'Success',
                message: 'Bank Details saved successfully !',
                variant: 'success'
            })
        );
    }) .catch(error => {
        this.error = error;
        
    }); 
}

}

In above LWC, on loading of the component wire method will fetch bank Account details and will display data on the page. When user would edit and click on Save button, it will call saveBankDetail method from JS component. In the JS component , you need to build the wrapper variable, in this case pass and then use it as a method variable while calling the apex method.