Skip to content

Is there a way to pass multiple (and different) parameters to an Apex Controller class from JS in Lightning Web Components (LWC)?

I’m currently stuck at a problem and was hoping someone here could help me. I also certainly hope this is the right place to ask it.

I’m trying to create a custom Invoice record with its corresponding Invoice Line records upon firing an event. I already have some logic in place to gather ID of selected rows in the JS.

I’ve gone so far as to be able to create the Invoice record (using LDS) and the Invoice Line records (using Apex), but can’t seem to pass the Invoice ID for the Invoice Line records. I know I’m able to create the records because it works when I tested this with a hardcoded Invoice ID.

Would it be possible to pass multiple parameters of List and String to an Apex method in LWC?

I would appreciate any help. Thanks in advance!


    selectedRowsEvent(event) {
    ...some codes here...
    this.selectedRecords = Array.from(conIds);
    handleSave() {
         ...some codes here...
        .then(invoice => {
            **this.invId = invoice.Id;**
            **createInvLines({ lstConIds : this.selectedRecords, invoiceId : this.invId})**
        }).catch(error => {
          ...some codes here...


    public static void createInvLines(list<Id> lstConIds, string invoiceId){
        if(lstConIds.size() > 0){
            List<OpportunityLine__c> oppLst = new List<OpportunityLine__c>([SELECT Id, Description__c FROM OpportunityLine__c WHERE Id = :lstConIds]);
            try {
                List<InvoiceLine__c> lstInvLinesToInsert = new List<InvoiceLine__c>();
                for(OpportunityLine__c idCon : oppLst) {
                    lstInvLinesToInsert.add(new InvoiceLine__c(**InvoiceId__c = invoiceId**, Description__c = idCon.Description__c));
                if(!lstInvLinesToInsert.isEmpty()) {
                    insert lstInvLinesToInsert;
            catch(Exception ex) {
                throw new AuraHandledException(ex.getMessage());


Yes, you can pass complex parameters to methods marked as @AuraEnabled. On client side it’ll be a JSON object with right field names, like you already have { lstConIds : this.selectedRecords, invoiceId : this.invId}. On Apex side it can be a function with multiple arguments or just 1 argument (some helper wrapper class, again with right field names). Salesforce will “unpack” that JSON for you and put into right fields before your code is called.

Your preference which would be cleaner. I tend to use wrappers. If you have a reusable service-like function and you want to add some optional parameters later – you’d simply put new field in wrapper class and job done. Might be not as easy to add a new parameter to function used in other apex code, bit messier.

(in your scenario I’d definitely try to create invoice and line items as 1 call so if anything fails – the normal transaction rollback will help you. if one of items fails – you don’t want to be left with just invoice header, right?)

Have you seen ? it’s a wall of text but it mentions interesting example, search for “apexImperativeMethodWithParams” in there.

Look at JS file here: And see how it calls

ApexTypesController {
    public static String checkApexTypes(CustomWrapper wrapper) {

Where CustomWrapper is

public with sharing class CustomWrapper {
    class InnerWrapper {
        public Integer someInnerInteger { get; set; }
        public String someInnerString { get; set; }
    public Integer someInteger { get; set; }
    public String someString { get; set; }
    public List<InnerWrapper> someList { get; set; }