Dynamic Add Delete Row In Lightning Component

In below example I’m adding account record in Salesforce Lightning Component with Add Delete Rows functionality.

Here I’ve created 2 lightning components and 2 lightning events, by these lightning components you can create multiple records as your requirement by Adding or Deleting new rows.

Step1 : Create Lightning Event “AddRowEvent.evt”

<aura:event type="COMPONENT" description="Event to add row"></aura:event>

Step2 : Create Lightning Event “DeleteRowEvent.evt”

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

Step3 : Create Lightning Component “Child.cmp”.

<aura:component >    
    <!--Attribute for store single Account object instance--> 
    <aura:attribute name="AccountInstance" type="Account"/>
    <!--Attribute for store Index of Particular Instance --> 
    <aura:attribute name="rowIndex" type="String"/>
    <!-- Register 2 Lightning Event for handle add or Delete rows on Parent Component  --> 
    <aura:registerEvent name="DeleteRowEvent" type="c:DeleteRowEvent"/> 
    <aura:registerEvent name="AddRowEvent" type="c:AddRowEvent"/> 
    <!-- Table Row -->   
    <tr class="slds-text-title_caps">
            {!v.rowIndex + 1}
            <ui:inputText class="slds-input" value="{!v.AccountInstance.Name}"/>
            <ui:inputText class="slds-input" value="{!v.AccountInstance.AccountNumber}"/>
            <ui:inputPhone class="slds-input" value="{!v.AccountInstance.Phone}"/>
            <!-- conditionally Display Add or Delete Icons, if rowIndex is 0 then show add row Icon else show delete Icon--> 
            <aura:if isTrue="{!v.rowIndex == 0}">
                <a onclick="{!c.addRow}">
                    <lightning:icon iconName="utility:add" class="slds-icon slds-icon_small" size="small" alternativeText="Add"/>
                    <span class="slds-assistive-text">Add</span>
                <aura:set attribute="else">
                    <a onclick="{!c.deleteRow}">
                        <lightning:icon variant="error" iconName="utility:delete" class="slds-icon slds-icon_small" size="small" alternativeText="Delete"/>
                        <span class="slds-assistive-text">Delete</span>

Step4 : Add “Child.cmp” controller “ChildController.js” method.

  • “addRow” method to add row.
  • “deleteRow” method to delete row.
    addRow : function(component, event, helper){
        //Execute the AddRowEvent Lightning Event 
    deleteRow : function(component, event, helper){
        //Execute the DeleteRowEvent Lightning Event and pass the deleted Row Index to Event attribute
        component.getEvent("DeleteRowEvent").setParams({"indexVar" : component.get("v.rowIndex") }).fire();

Step5 : Create Apex Controller “AuraSampleController.apxc”.

  • “SaveAccounts” method to save list of Account.
public with sharing class AuraSampleController{
    public static void SaveAccounts(List<Account> accList){
        Insert accList;

Step6 : Create Lightning Component “Parent.cmp”

<aura:component controller="AuraSampleController" Implements="flexipage:availableForRecordHome,force:hasRecordId">
    <!--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 execute from Child Component-->    
    <aura:handler name="DeleteRowEvent" event="c:DeleteRowEvent" action="{!c.removeDeletedRow}"/>
    <aura:handler name="AddRowEvent" event="c:AddRowEvent" action="{!c.addRow}"/>
    <!--Aura Attribute for store Account Object List as Array-->    
    <aura:attribute name="AccountList" type="Account[]"/> 
    <!--Header Part-->        
    <div class="slds-page-header">
        <h1 class="slds-page-header__title">Create Multiple Accounts in Lightning</h1>
    <!--Table Part-->           
    <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate">#</div>
                <th scope="col">
                    <div class="slds-truncate" title="Account Name">Account Name</div>
                <th scope="col">
                    <div class="slds-truncate" title="Account Number">Account Number</div>
                <th scope="col">
                    <div class="slds-truncate" title="Phone">Phone</div>
                 <th scope="col">
                    <div class="slds-truncate" title="Action">Action</div>
            <!--Iterate the child Component for display Table rows 
               with pass the List Item Index for track the Every child Component 
               and pass each List Account Instance -->         
            <aura:iteration items="{!v.AccountList}" var="item" indexVar="index">
                <c:Child AccountInstance="{!item}" rowIndex="{!index}" />
    <!--Save Button which is call Save js function on click --> 
    <button class="slds-button slds-button_brand"  onclick="{!c.Save}">Save</button>

Step7 : Add “Parent.cmp” controller “ParentController.js” method.

  • “doInit” method for component load.
  • “Save” method for data Save.
  • “addRow” method to add new row.
  • “removeDeletedRow” method to remove delete row from list.
    // function call on component Load
    doInit: function(component, event, helper) {
        // create a Default RowItem [Account Instance] on first time Component Load
        // by call this helper function  
        helper.createObjectData(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 "Account Name" will not be blank on each row.
        if (helper.validate(component, event)) {
            // call the apex class method for save the Account List
            // with pass the contact List attribute to method param.  
            var action = component.get("c.SaveAccounts");
                "accList": component.get("v.AccountList")
            // set call back 
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (state === "SUCCESS") {
                    // if response if success then reset the 'AccountList' Attribute 
                    // and call the common helper method for create a default Object Data to Account List 
                    component.set("v.AccountList", []);
                    helper.createObjectData(component, event);
                    alert('Account records saved successfully');
            // enqueue the server side action  
    // function for create new object Row in Contact List 
    addRow: function(component, event, helper) {
        // call the comman "createObjectData" helper method for add new Object Row to List  
        helper.createObjectData(component, event);
    // function for delete the row 
    removeDeletedRow: function(component, event, helper) {
        //get the selected row Index for delete, from Lightning Event Attribute  
        var index = event.getParam("indexVar");
        //get the all List (AccountList attribute) and remove the Object Element Using splice method    
        var AllRowsList = component.get("v.AccountList");
        AllRowsList.splice(index, 1);
        //set the AccountList after remove selected row element  
        component.set("v.AccountList", AllRowsList);

Step8 : Add “Parent.cmp” component helper “ParentHelper.js” method.

  • “createObjectData” method for create new instance of Account object.
  • “validate” method to validate Account Name.
    createObjectData: function(component, event) {
        //get the AccountList from component and add(push) New Object to List  
        var RowItemList = component.get("v.AccountList");
            'sobjectType': 'Account',
            'Name': '',
            'AccountNumber': '',
            'Phone': ''
        // set the updated list to attribute (AccountList) again    
        component.set("v.AccountList", RowItemList);
    //helper function for check if Account Name is not null/blank on save  
    validate: function(component, event) {
        var isValid = true;
        var allAccountRows = component.get("v.AccountList");
        for (var indexVar = 0; indexVar < allAccountRows.length; indexVar++) {
            if (allAccountRows[indexVar].Name == '') {
                isValid = false;
                alert('Account Name Cannot be blank on row number ' + (indexVar + 1));
        return isValid;

Step9 : Create Lightning App “MyDemo.app”.

<aura:application implements="force:appHostable" extends="force:slds">
    <c:Parent />    

Output :

Create Account Record :

Created Account Records :