Lightning Nested Action Call :

This chapter explains about Nested Action Call in lightning

In lightning , you would come across scenerios where after completion of apexMethod1 ,with the result , you must do one more call to apexMethod2 
This is called nested action call in lightning

A typical scenerio explained in this program is 
Based on user name, we are finding the account object and based on the account object we are getting the related lead's or opportunities based on user chosen value.


The below program shows an example of Nested Action Call in salesforce

Create an apex class and save it as ApexForActionExecution

/*


 * created by 		:		Shiva RV
 * Date				:		21-10-2018
 * Description		:		Contains methods for Nested Action Component ,also for using Promise type
 
  
*/

public class ApexForActionExecution {

@AuraEnabled    
public static Account getAccountFromName(String name)
{
    Account acc;

    try{
		acc=[select id from account where name=:name limit 1];
    }
    catch(Exception e)
    {
        acc=null;
        throw  new AuraHandledException('No Account is present');
    }
    return acc;
}
@AuraEnabled    
public static List<opportunity> getOpportunitiesFromAccount(Id AccountId)
{
   List<opportunity> opportunityList;

    try{
		opportunityList=[select id,name from opportunity where accountid=:AccountId limit 5];
    }
    catch(Exception e)
    {
        opportunityList=null;
    }
   return opportunityList;
}  
  @AuraEnabled    
public static List<Lead> getLeadsFromAccount(Id AccountId)
{
    List<Lead> leadList;

    try{
		leadList=[select id,name,shivalight__customAccountLookup__c from lead where shivalight__customAccountLookup__c=:AccountId limit 5];
    }
    catch(Exception e)
    {
        leadList=null;
        
    }
    return leadList;
  }    
}

Create the Lightning Event as below  and save it as  NestedActionComponent

<!--


 * created by 		:		Shiva RV
 * Date				:		21-10-2018
 * Description		:		action which need's to be executes after completion 
							of another action in lightning
      				  /* Hypothetical Scenerio :
						 First fetch FewAccount and then
						 Fetch all opportunity of the chosen account
  
-->

<aura:component controller="ApexForActionExecution">
    
    <aura:attribute name="accountName" type="String"></aura:attribute>
    <aura:attribute name="AccountRecord" type="Account"></aura:attribute>
    <aura:attribute name="associatedOpps" type="List"></aura:attribute>
    <aura:attribute name="associatedLeads" type="List"></aura:attribute>

    <aura:attribute name="isResultCompleted" type="Boolean" default="false"></aura:attribute>

     <aura:attribute name="subTypeOptions" type="List" default="[
             {'label': 'Lead', 'value': 'lead'},
             {'label': 'Opportunity', 'value': 'opportunity'}
       ]"/>
    <aura:attribute name="chosenTypeOfSubObject" type="String"></aura:attribute>
    
        
    <lightning:radioGroup 
        aura:id="mygroup"
        name="radioButtonGroup"
        label="SubTypeOption"
        options="{! v.subTypeOptions }"
        value="{! v.chosenTypeOfSubObject}"
        onchange="{! c.radioValueChange}"
    />
    <lightning:input type="text" name="acountName" value="{!v.accountName}" label="Account Name" />
	<lightning:Button name="fetch Accounts and Related Records" label="fetch Accounts" onclick="{!c.fetchAccounts}"></lightning:Button>
       
    <aura:If isTrue="{! and (v.chosenTypeOfSubObject=='opportunity',v.isResultCompleted==true)}">
    <table>
        <tr>
     <th>Id</th>   <th>Opportunity Name</th>
            </tr>
    <aura:Iteration items="{!v.associatedOpps}" var="indOpp" >
      <tr> <td>{!indOpp.Id}</td>
          <td>{!indOpp.Name}</td> </tr>
        </aura:Iteration>
    </table>
    </aura:If>
    <aura:If isTrue="{! and (v.chosenTypeOfSubObject=='lead',v.isResultCompleted==true)}">
     <table>
         <tr>
     <th>Id</th>   <th>Lead Name</th>
         </tr>
        <aura:Iteration items="{!v.associatedLeads}" var="indLead">
            <tr>           
 		<td> {!indLead.Id}</td>
            <td> {!indLead.Name}</td>
            </tr>
        </aura:Iteration>
		</table>
    </aura:If>
    </aura:component>
NestedActionComponent Js Controller Code:
({
	fetchAccounts : function(component, event, helper) {
        var chosenSubRecordType=component.get("v.chosenTypeOfSubObject");
        component.set("v.chosenTypeOfSubObject",chosenSubRecordType);
        console.log(chosenSubRecordType);
        var accountName=component.get("v.accountName");
        //return if any of the value is null;
        //error handling has a new section allocated, for now just keep it as alert box
        if( (!chosenSubRecordType) || (!accountName))
        {
            alert("please enter chosenSubRecordType and accountName fields");
            
            return;
        }
        component.set("v.isResultCompleted",false);
        helper.fetchAccountsHelper(component,chosenSubRecordType,accountName,helper);
		
    },
    
    radioValueChange:function(component,event,helper)
    {
        console.log("in radioValueChange method ");
      component.set("v.isResultCompleted",false);  
    },
})
NestedActionComponent Helper Controller Code:
({
	fetchAccountsHelper : function(component,chosenSubRecordType,accountName,helper) {
		 var action= component.get("c.getAccountFromName");
        action.setParams({"name" : accountName});
         action.setCallback(this, function(response)
         {
         	var state = response.getState();
         	if (state === "SUCCESS") 
         	{
                console.log(response.getReturnValue());
               component.set("v.AccountRecord",response.getReturnValue());
               helper.helperLevel2Function(component,chosenSubRecordType,response.getReturnValue().Id);
                
         	}
         	else
         	{
                
         	}    
         });
         $A.enqueueAction(action);
	},
    
    helperLevel2Function : function(component,chosenSubRecordType,accountId)
    {
        console.log("in helper2 "+chosenSubRecordType);
         var action;
        if(chosenSubRecordType=="lead")
            
           action = component.get("c.getLeadsFromAccount");
        else
            action=component.get("c.getOpportunitiesFromAccount");
        action.setParams({"AccountId" : accountId});
         action.setCallback(this, function(response)
         {
         	var state = response.getState();
         	if (state === "SUCCESS") 
         	{
                if(chosenSubRecordType=="lead")
                {
                    console.log(response.getReturnValue());
                   	component.set("v.associatedLeads",response.getReturnValue());
                    console.log(component.get("v.associatedLeads"));
                    
                    component.set("v.associatedOpps",[]);


                }
                else
                {
                    console.log(response.getReturnValue());
					
                    component.set("v.associatedOpps",response.getReturnValue());
					
                    component.set("v.associatedLeads",[]);
                }
                //to show in the list iteration
                component.set("v.isResultCompleted",true);
         	}
         	else
         	{
                
         	}    
         });
         $A.enqueueAction(action);
    }
})
Below is the hello world App code:
<!--


 * created by 		:		Shiva RV
 * Date				:		13-10-2018
 * Description		:		Hello World Lighting App
  
-->

<aura:application extends="force:slds">
 <!--
	this is the lightning app where you can place html codes , associate js code
	also can embed lightning component to it 
 -->
    
    <!-- Nested action Component demo -->
    <c:NestedActionComponent></c:NestedActionComponent> 
  

</aura:application>
Output:

Key Notes :
*If two actions are run independently , we can't guarantee the execution order
*Hence if next apex method 2 call must be made inside the callback of method1 as explained in the above program