function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Paul LightningPaul Lightning 

How to create more than one record with lightning components

Dear fellow experts,

I am building a lightning component where I am using a form with fields in order to create multiple opportunities.

I am already able to create multiple opportunities in my database but I am not able to create multiple local opportunities yet.
I want to first create multiple local opportunities that I can display as a list with certain fields that can be manually adjusted.

I very much appreciate help, since I couldn't find any solution although I was searching for it for one week!

Here is my code:

createMultipleOpportunities.cmp

<!-- form with fields that are used to create multiple opportunities, i don't think this code is relevant, therefore not shown here-->

<!--variable that is supposed to generate a collection or array where i can store my new local objects-->

<aura:attribute name="newChildOpportunities" type="Opportunity[]"/>

<!--Button that is supposed to create local opportunities-->
<ui:button label="Create child Opportunities" press="{!c.createChildOpportunitieslocally}"/>

<!--this part is supposed to iterate through all child opportunities, doesn't display them yet-->
 <table class="slds-table slds-table--bordered">
      <thead>
        <tr>
           <th scope="col"><span class="slds-truncate">Name</span></th>
           <th scope="col"><span class="slds-truncate">Child Deal Size</span></th>
        </tr>
      </thead>
      <tbody>
<aura:iteration items="{!v.newChildOpportunities}" var="opportunity">
   <tr>
     <td>{!opportunity.Name}</td>
     <td><ui:inputCurrency aura:id="childAmount" value="{!v.childDealSize}"/></td>    
  </tr>
</aura:iteration>
</tbody>
</table>

createMultipleOpportunitiesController.js
({
    createChildOpportunitieslocally: function(component, event, helper) {
        var i=0;
        for(i=0;i<5;i++){
            component.set("v.newChildOpportunity.Name", "child " + i);
            component.set("v.newChildOpportunity.Deal_Size__c", 500);
        }
    },
})

Let me know if you need further information.

Thank you in advance for your help :)!

Best regards,
Paul
Paul LightningPaul Lightning
In other words, I am looking for a solution in order to create temporary records that can be edited before they get saved in the database.

I appreciate your help!

Best regards,
Paul
Ashutosh kumar yadavAshutosh kumar yadav
parent component.......................


<aura:component controller="insertRecordController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <!--Init handler which is call doInit js function on component Load-->  
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
  
 <!--Event handler for Add and Delete Row Event which is fire from Child Component-->    
   
    <aura:handler name="deleteContactRowEVT" event="c:deleteContactRowEVT" action="{!c.removeDeletedContactRow}"/>
    <aura:handler name="addContactRowEVT" event="c:addContactRowEVT" action="{!c.addNewContactRow}"/>
    
    <aura:handler name="DeleteRowEvt" event="c:DeleteRowEvt" action="{!c.removeDeletedOpportunityRow}"/>
    <aura:handler name="AddRowEvt" event="c:AddNewRowEvt" action="{!c.addNewOpportunityRow}"/>
 
   
 <!--Aura Attribute for store Contact and Opportunity Object List as Array--> 
    <aura:attribute name="Acc" type="Account[]"/>
    <aura:attribute name="AccountId" type="String"/>
    <aura:attribute name="contactList" type="Contact[]"/> 
    <aura:attribute name="opportunityList" type="Opportunity[]"/> 
 
 <!--Header Part-->        
    <div class="slds-page-header">
        <h1 class="slds-page-header__title">Create Multiple Contacts and opportunities Of an Account With Add/Delete Rows Dynamically</h1>        
    </div>    
    <div class="slds-page-header">
        <h1 class="slds-page-header__title"> Account detail </h1>       
    </div>    
    <!--Table Account -->           
    <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate">S.No</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Account Name">Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Phone">Phone</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Email">Email</div>
                </th>
            </tr>
        </thead>   
        <tbody>            
                <aura:iteration items="{!v.Acc}" var="item" indexVar="index">
                <c:dynamicAccountComponent AccountInstance="{!item}" rowIndex="{!index}" />
            </aura:iteration> 
        </tbody>
    </table>
    <br/>
    
   <div class="slds-page-header">
        <h1 class="slds-page-header__title"> Contact detail </h1>
        
    </div> 
    
    
 <!--Table Part for contact -->           
    <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate">S.No</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="First Name">First Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Last Name">Last Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Phone">Phone</div>
                </th>
            </tr>
        </thead>   
        <tbody>
           <!--Iterate the child Component for display Table rows 
               with pass the List Item Index for track the Every child Component 
               and pass each List Contact Instance -->         
            <aura:iteration items="{!v.contactList}" var="item" indexVar="index">
                <c:dynamicRowItemComponent ContactInstance="{!item}" rowIndex="{!index}" />
            </aura:iteration>
        </tbody>
    </table>
    <br/>
    
    
    <div class="slds-page-header">
        <h1 class="slds-page-header__title"> Opportunity detail </h1>
        
    </div>
    
    
    <!--Table Part-->           
    <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate">S.No</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Name">Opportunity Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="stage">Stage Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="CloseDate">Close Date</div>
                </th>
            </tr>
        </thead>   
        <tbody>
           <!--Iterate the child Component for display Table rows 
               with pass the List Item Index for track the Every child Component 
               and pass each List Contact Instance -->         
            
            <aura:iteration items="{!v.opportunityList}" var="item" indexVar="index">
                <c:dynamicOpportunity opportunityInstance="{!item}" rowIndex="{!index}" />
            </aura:iteration>
        </tbody>
    </table>
    
    <br/> 
    <!--Save Button which is call Save js function on click --> 
    <button class="slds-button slds-button_brand" onclick="{!c.Save}">Save</button>
</aura:component>


parent component controller...............................................


({
    doInit: function(component, event, helper) {
        // create a Default RowItem [Contact Instance] on first time Component Load
        // by call this helper function  
        helper.createObjectDataContact(component, event);
        helper.createObjectDataAccount(component, event);
        helper.createObjectDataOpportunity(component, event);
    },
    
    
    
 
   // function for save the Records 
    Save: function(component, event, helper) {
        // first call the helper function in if block which will return true or false.
        // this helper function check the "first Name" will not be blank on each row.
        if (helper.validateRequiredContact(component, event) ) {
            // call the apex class method for save the Contact List
            // with pass the contact List attribute to method param.  
            var action = component.get("c.saveAccConOppRecord");
            action.setParams({
                "acc":component.get("v.Acc"),
                "conList": component.get("v.contactList"),
                "oppList": component.get("v.opportunityList"),
            });
            // set call back 
            action.setCallback(this, function(response) {
                var state = response.getState();
                //alert(response.getReturnValue);
                if (state === "SUCCESS") {
                   
                    
                    //component.set("v.Acc");
                    //helper.createObjectDataAccount(component, event);
                    
                    component.set("v.contactList", []);
                    helper.createObjectDataContact(component, event);
                    
                    component.set("v.opportunityList", []);
                    helper.createObjectDataOpportunity(component, event);
                    
                   
                    alert('Records created successfully !! ');
                }
            });
            // enqueue the server side action  
            $A.enqueueAction(action);
        }
    },
 
    
    
    
    
    
    // function for create new object Row in Contact List 
    addNewContactRow: function(component, event, helper) {
        // call the comman "createObjectData" helper method for add new Object Row to List  
         helper.createObjectDataContact(component, event);
    },
 
    
    
    addNewOpportunityRow: function(component, event, helper) {
        // call the comman "createObjectData" helper method for add new Object Row to List  
         helper.createObjectDataOpportunity(component, event);
    },
 
    
    
    
    // function for delete the row 
    removeDeletedContactRow: function(component, event, helper) {
        // get the selected row Index for delete, from Lightning Event Attribute  
        var index = event.getParam("indexVar");
        // get the all List (contactList attribute) and remove the Object Element Using splice method    
        var AllRowsList = component.get("v.contactList");
        AllRowsList.splice(index, 1);
        // set the contactList after remove selected row element  
        component.set("v.contactList", AllRowsList);
    },
    
    removeDeletedOpportunityRow: function(component, event, helper) {
        // get the selected row Index for delete, from Lightning Event Attribute  
        var index = event.getParam("indexVar");
        // get the all List (contactList attribute) and remove the Object Element Using splice method    
        var AllRowsList = component.get("v.opportunityList");
        AllRowsList.splice(index, 1);
        // set the contactList after remove selected row element  
        component.set("v.opportunityList", AllRowsList);
    },
})


parent component helper......................................................


({
    createObjectDataContact: function(component, event) {
        // get the contactList from component and add(push) New Object to List  
        var RowItemList = component.get("v.contactList");
        RowItemList.push({
            'sobjectType': 'Contact',
            'FirstName': '',
            'LastName': '',
            'Phone': ''
        });
        // set the updated list to attribute (contactList) again    
        component.set("v.contactList", RowItemList);
    },
    
    
    createObjectDataAccount: function(component, event) {
        // get the contactList from component and add(push) New Object to List  
        var RowItem = component.get("v.Acc");
        RowItem.push({
            'sobjectType': 'Account',
            'Name': '',
            'Phone': '',
            'Email': ''
        });
        // set the updated acc to attribute acc again    
        component.set("v.Acc", RowItem);
    },
    
    createObjectDataOpportunity: function(component, event) {
        // get the contactList from component and add(push) New Object to List  
        var RowItemList = component.get("v.opportunityList");
        RowItemList.push({
            'sobjectType': 'Opportunity',
            'Name': '',
            'StageName': '',
            'CloseDate': ''
        });
        // set the updated list to attribute (contactList) again    
        component.set("v.opportunityList", RowItemList);
    },







   // helper function for check if first Name is not null/blank on save  
    validateRequiredAccount: function(component, event) {
        var isValid = true;
        var allContactRows = component.get("v.Acc");
        for (var indexVar = 0; indexVar < allContactRows.length; indexVar++) {
            if (allContactRows[indexVar].Name == '') {
                isValid = false;
                alert('First Name Can\'t be Blank on Row Number ' + (indexVar + 1));
            }
        }
        return isValid;
    },



    
    // helper function for check if first Name is not null/blank on save  
    validateRequiredContact: function(component, event) {
        var isValid = true;
        var allContactRows = component.get("v.contactList");
        for (var indexVar = 0; indexVar < allContactRows.length; indexVar++) {
            if (allContactRows[indexVar].FirstName == '') {
                isValid = false;
                alert('First Name Can\'t be Blank on Row Number ' + (indexVar + 1));
            }
        }
        return isValid;
    },
    
    validateRequiredOpportunity: function(component, event) {
        var isValid = true;
        var allOpportunityRows = component.get("v.opportunityList");
        for (var indexVar = 0; indexVar < allOpportunityRows.length; indexVar++) {
            if (allOpportunityRows[indexVar].Name == '') {
                isValid = false;
                alert('Opportunity Name Can\'t be Blank on Row Number ' + (indexVar + 1));
            }
        }
        return isValid;
    },
})


Account child component.............................................


<aura:component >
    <!-- Aura Attribute for store single Contact[standard Object] Instance
        And Store Index of Particular Instance -->
   <aura:attribute name="AccountInstance" type="Account"/>
   <aura:attribute name="rowIndex" type="String"/>
   
   
   <!-- Table Row -->  
   <tr class="slds-text-title_caps">
       <td>
           {!v.rowIndex +1}
       </td>
       <td>
           <ui:inputText class="slds-input" value="{!v.AccountInstance.Name}"/>
       </td>
       <td>
           <ui:inputText class="slds-input" value="{!v.AccountInstance.Phone}"/>
       </td>
       <td>
           <ui:inputText class="slds-input" value="{!v.AccountInstance.Email}"/>
       </td>
       
       
   </tr>
</aura:component>




 
Ashutosh kumar yadavAshutosh kumar yadav
contact child component.......................................................

<aura:component >
      <!-- Aura Attribute for store single Contact[standard Object] Instance
         And Store Index of Particular Instance --> 
    <aura:attribute name="ContactInstance" type="Contact"/>
    <aura:attribute name="rowIndex" type="String"/>
    
    <!-- Register 2 Lightning Event for handle add or Delete rows on Parent Component  --> 
     
    <aura:registerEvent name="deleteContactRowEVT" type="c:deleteContactRowEVT"/> 
    <aura:registerEvent name="addContactRowEVT" type="c:addContactRowEVT"/> 
    
    <!-- Table Row -->   
    <tr class="slds-text-title_caps">
        <td> 
            {!v.rowIndex + 1}
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!v.ContactInstance.FirstName}"/>
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!v.ContactInstance.LastName}"/>
        </td>
        <td>
            <ui:inputPhone class="slds-input" value="{!v.ContactInstance.Phone}"/>
        </td>
        <td>
            <!-- conditionally Display Add or Delete Icons
                 if rowIndex is 0 then show Add New Row Icon else show delete Icon
             --> 
            <aura:if isTrue="{!v.rowIndex == 0}">
                <a onclick="{!c.AddNewContactRow}">
                  <lightning:icon iconName="utility:add" class="slds-icon slds-icon_small" size="small" alternativeText="add"/>
                  <span class="slds-assistive-text">Add Icon</span>
                </a>    
              <aura:set attribute="else">
                  <a onclick="{!c.removeContactRow}">
                   <lightning:icon variant="error" iconName="utility:delete" class="slds-icon slds-icon_small" size="small" alternativeText="icon"/>
                   <span class="slds-assistive-text">Delete Icon</span>
                  </a>
              </aura:set> 
            </aura:if>
        </td> 
    </tr>
</aura:component>



contact child component controller.........................................

({
     AddNewContactRow : function(component, event, helper){
       // fire the AddNewRowEvt Lightning Event 
        component.getEvent("addContactRowEVT").fire();     
    },
    
    removeContactRow : function(component, event, helper){
     // fire the DeleteRowEvt Lightning Event and pass the deleted Row Index to Event parameter/attribute
       component.getEvent("deleteContactRowEVT").setParams({"indexVar" : component.get("v.rowIndex") }).fire();
    },
})


opportunity child component..................................................

<aura:component >
     <!-- Aura Attribute for store single Contact[standard Object] Instance
        And Store Index of Particular Instance -->
   <aura:attribute name="opportunityInstance" type="opportunity"/>
   <aura:attribute name="rowIndex" type="String"/>
   
   <!-- Register 2 Lightning Event for handle add or Delete rows on Parent Component  -->
   <aura:registerEvent name="DeleteRowEvt" type="c:DeleteRowEvt"/>
   <aura:registerEvent name="AddRowEvt" type="c:AddNewRowEvt"/>
   
   <!-- Table Row -->  
   <tr class="slds-text-title_caps">
       <td>
           {!v.rowIndex + 1}
       </td>
       <td>
           <ui:inputText class="slds-input" value="{!v.opportunityInstance.Name}"/>
       </td>
       <td>
           <ui:inputText class="slds-input" value="{!v.opportunityInstance.StageName}"/>
       </td>
       <td>
           <Lightning:Input class="slds-input" value="{!v.opportunityInstance.CloseDate}" type='Date' />
       </td>
       
       <td>
           <!-- conditionally Display Add or Delete Icons
                if rowIndex is 0 then show Add New Row Icon else show delete Icon
            -->
           <aura:if isTrue="{!v.rowIndex == 0}">
               <a onclick="{!c.AddNewOpportunityRow}">
                 <lightning:icon iconName="utility:add" class="slds-icon slds-icon_small" size="small" alternativeText="add"/>
                 <span class="slds-assistive-text">Add Icon</span>
               </a>    
             <aura:set attribute="else">
                 <a onclick="{!c.removeOpportunityRow}">
                  <lightning:icon variant="error" iconName="utility:delete" class="slds-icon slds-icon_small" size="small" alternativeText="icon"/>
                  <span class="slds-assistive-text">Delete Icon</span>
                 </a>
             </aura:set>
           </aura:if>
       </td>
   </tr>
</aura:component>


opportunity child component controller.................................


({
     AddNewOpportunityRow : function(component, event, helper){
      // fire the AddNewRowEvt Lightning Event
       component.getEvent("AddRowEvt").fire();    
   },
   
   removeOpportunityRow : function(component, event, helper){
    // fire the DeleteRowEvt Lightning Event and pass the deleted Row Index to Event parameter/attribute
      component.getEvent("DeleteRowEvt").setParams({"indexVar" : component.get("v.rowIndex") }).fire();
   }
})

DeleteRowEvt...................................
<aura:event type="COMPONENT" description="Event to remove Row" >
 <aura:attribute name="indexVar" type="Integer" description="Use For Delete Row" />
</aura:event>



controller Apex class...................................................

public with sharing class insertRecordController  {
 
@AuraEnabled
   public static Id saveAccConOppRecord(List<Account> acc,List<Contact> conList,List<Opportunity> oppList){
       Id AccountId;
     
       system.debug(acc);
       system.debug(conList);
       system.debug(oppList);
       
      SavePoint sp = Database.setSavePoint();
       try{
           //inserting Account
           insert acc;
         
           //Account a=[SELECT Id FROM Account WHERE CreatedDate=TODAY LIMIT 1 ];
           for(Account a: acc){
               
               AccountId=a.Id;}
           
           //inserting List of Contact associated with Account id
           List<Contact> contactToInsert=new List<Contact>();
           for(Contact con : conList){
               con.AccountId=AccountId;
               contactToInsert.add(con);
           }
           insert contactToInsert;
           
           
           //inserting List of Opportunity associated with Account id
           List<Opportunity> OpportunityToInsert=new List<Opportunity>();
           for(Opportunity opp : oppList){
               opp.AccountID  = AccountId;
               OpportunityToInsert.add(opp);
           }
           insert OpportunityToInsert;
         
       }
       catch(Exception e){
           Database.rollback(sp);  // if, is there any error occure than transaction would be rolled back to same stage of database.
       }
        return AccountId;
   }
   
   
}


Send a message
parent compo

accWithConWithOpp.cmp

 child component name
//dynamicAccountComponent 1.for account
// dynamicRowItemComponent -for contact
//dynamicOpportunity   - for opportunity



<aura:application extends="force:slds">
<!-- <c:DataProcessor /> -->
    <c:accWithConWithOpp />
 
</aura:application>