Return data from multiple objects in a single apex method in Lightning component framework
There are primarily two approaches
1. Server side Wrapper in apex
This can be handy if the number of rows and query are within apex governor limit .Example can be lets say you return less than 50K rows and total number of queries you need is less than 100 .
You can generate a wrapper schema like above
public class AccountContactWrapper {
@AuraEnabled
public list<Account> accounts {get;set;}
@AuraEnabled
public list<contact> contacts {get;set;}
public AccountContactWrapper(){
this.accounts = new list<Account>();
this.contacts = new list<contacts>();
}
}
public class Response{
@AuraEnabled
public static AccountContactWrapper method(){
AccountAndContact acWrapper = new AccountAndContact();
acWrapper.accounts = [select id, name from account limit 20000];
acWrapper.contacts = [select id, name from contact LIMIT 20000];
return acWrapper;
}
}
2.Using Promise In Javascript
Javascript ES6 Promises are commonly used to call one method after other and resolve them as you wish on the client side .The benefit of this method is you can chain multiple server side calls .
Here is a pattern to help call one function after the other
accountPromise.then(
$A.getCallback(function(result){
// We have the account - set the attribute
cmp.set('v.account', result);
// return a promise to retrieve a contact
var contAction = cmp.get("c.GetContact");
var contParams={"accountIdStr":accId};
contAction.setParams(contParams);
var contPromise=self.executeAction(cmp, contAction);
return contPromise;
})
)
.then(
$A.getCallback(function(result){
// We have the contact - set the attribute
cmp.set('v.contact', result);
})
.catch(
$A.getCallback(function(error){
// Something went wrong
alert('An error occurred : ' + e.message);
})
);
Here is a neat blogpost that shows how to use them
If Promises are hard to wrap your heads around you can use below simplified callback pattern as well
// better version - separate callback functions
getAccountOwner2 : function(cmp, event, helper) {
// cleanup
cmp.find("contactName").set('v.value', '');
cmp.find("accountName").set('v.value', '');
cmp.find("ownerName").set('v.value', '');
var getContact = cmp.get("c.getContact");
getContact.setParams( {"contactId": cmp.get("v.recordId")} );
getContact.setCallback(this, contactCallback);
$A.enqueueAction(getContact);
function contactCallback(contact) {
contact = contact.getReturnValue();
cmp.find("contactName").set('v.value', contact.Name);
var getAccount = cmp.get("c.getAccount");
getAccount.setParams( {"accountId": contact.AccountId} );
getAccount.setCallback(this, accountCallback);
$A.enqueueAction(getAccount);
}
function accountCallback(account) {
account = account.getReturnValue();
cmp.find("accountName").set('v.value', account.Name);
var getUser = cmp.get("c.getUser");
getUser.setParams( {"userId": account.OwnerId} );
getUser.setCallback(this, userCallback);
$A.enqueueAction(getUser);
}
function userCallback(user) {
user = user.getReturnValue();
cmp.find("ownerName").set('v.value', user.Name);
}
}
You can simply use a map as output parameter and return for example:
return new Map<string,object> {'account': acc, 'contact': con}