Add Delete Row Dynamic In Lightning Component : Sample Code

Lightning Component

Hi Guys,

Today in this post we are going to learn, How to Add Delete Rows Dynamic In Salesforce Lightning Component By Using Client Side JavaScript Controller.

In this post, we are created 2 sample lightning component, by these lightning components You can create multiple records as your requirement by Adding or Deleting new rows on UI. we will also make, ‘first name’ as a required Input field

Add Delete Rows Dynamic In Lightning Component sfdcmonkey
Component Output:

 

Component Blue Print :

Add Delete Rows Dynamic In Lightning Component sfdcmonkey

For done this we have created 2 Lightning Components and 2 Lightning Events for pass values/actions from child component to parent. Events can contain attributes that can be set before the event is fired and read when the event is handled.

Step 1 : Create Lightning Event : AddNewRowEvt.evt

From Developer Console >> File >> New >> Lightning Event

<aura:event type="COMPONENT" description="Use For Add New Row"></aura:event>
Step 2 : Create Lightning Event : DeleteRowEvt.evt

From Developer Console >> File >> New >> Lightning Event

<aura:event type="COMPONENT" description="Event to remove Row" >
    <aura:attribute name="indexVar" type="Integer" description="Use For Delete Row" />
</aura:event>
Step 3 : Create Lightning Component : dynamicRowItem.cmp [Child Component]

From Developer Console >> File >> New >> Lightning Component

<!-- sfdcMonkey.com -->
<!-- Child Lightning Component for Create New Row Instance-->
<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="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.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.AddNewRow}">
                  <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.removeRow}">
                   <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>
  • See Code Comments.
JavaScript Controller : dynamicRowItemController.js
({
    AddNewRow : function(component, event, helper){
       // fire the AddNewRowEvt Lightning Event 
        component.getEvent("AddRowEvt").fire();     
    },
    
    removeRow : 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();
    }, 
  
})
  • See Code Comments.
Step 4 : Create Apex Controller : addDeleteController.apxc

From Developer Console >> File >> New >> Apex Class

public with sharing class addDeleteController {
   @AuraEnabled
    public static void saveContacts(List<Contact> ListContact){
        Insert ListContact;
    }
}
  • By above apex controller we are save the contacts.
Step 5 : Create Lightning Component : dynamicRow.cmp [Parent Component]

From Developer Console >> File >> New >> Lightning Component

<!--sfdcmonkey.com-->
<!--Parent Lightning Compomemt-->
<aura:component controller="addDeleteController" 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 fire from Child Component-->    
    <aura:handler name="DeleteRowEvt" event="c:DeleteRowEvt" action="{!c.removeDeletedRow}"/>
    <aura:handler name="AddRowEvt" event="c:AddNewRowEvt" action="{!c.addNewRow}"/>
 
 <!--Aura Attribute for store Contact Object List as Array-->    
    <aura:attribute name="contactList" type="Contact[]"/> 
 
 <!--Header Part-->        
    <div class="slds-page-header">
        <h1 class="slds-page-header__title">Create Multiple Contacts, With Add/Delete Rows Dynamically</h1>
        <p class="slds-text-body_small slds-line-height_reset">By sfdcmonkey.com</p>
    </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="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:dynamicRowItem ContactInstance="{!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>
  • See Code Comments.
JavaScript Controller : dynamicRowController.js
({

    // function call on component Load
    doInit: function(component, event, helper) {
        // create a Default RowItem [Contact 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 "first Name" will not be blank on each row.
        if (helper.validateRequired(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.saveContacts");
            action.setParams({
                "ListContact": component.get("v.contactList")
            });
            // set call back 
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (state === "SUCCESS") {
                    // if response if success then reset/blank the 'contactList' Attribute 
                    // and call the common helper method for create a default Object Data to Contact List 
                    component.set("v.contactList", []);
                    helper.createObjectData(component, event);
                    alert('record Save');
                }
            });
            // enqueue the server side action  
            $A.enqueueAction(action);
        }
    },

    // function for create new object Row in Contact List 
    addNewRow: 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 (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);
    },
})
  • See Code Comments.
JavaScript Helper : dynamicRowHelper.js
({
    createObjectData: 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);
    },
    // helper function for check if first Name is not null/blank on save  
    validateRequired: 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;
    },
})
  • See Code Comments.
From developer console >> file >> new >> Lightning Application
demo.app [Lightning Application]
<aura:application extends="force:slds">
    <c:dynamicRow/>
<!-- here c: is org. default namespace prefix-->
</aura:application>

Output:

Add Delete Rows Dynamic In Lightning Component sfdcmonkey

Related Resource:

Like our facebook page for new post updates. & Don’t forget to bookmark this site for your future reference.

if you have any suggestions or issue with it, you can post in comment box 🙂

 

47 comments

  • This page has an error. You might just need to refresh it. Action failed: c:dynamicRow$controller$Save [i is not defined] Failing descriptor: {c:dynamicRow$controller$Save}         i m getting error  can u help me out?

    • Hi jagannath,
      sorry my Typo mistake in the javaScript helper code of dynamicRowHelper [Line number 18].
      Please correct for loop last parameter, Use indexVar++ InsteadOf i++
      for (var indexVar = 0; indexVar < allContactRows.length; indexVar++) {

      Thanks for inform on this

  • This page has an error. You might just need to refresh it. i m getting the following errors can u help me out?

    Error in $A.getCallback() [Cannot read property ‘FirstName’ of null]

    Error in $A.getCallback() [Cannot read property ‘LastName’ of null]

    Error in $A.getCallback() [Cannot read property Phone’ of null]

    When click on Add button

    This page has an error. You might just need to refresh it.
    Action failed: c:dynamicRowItem$controller$AddNewRow [Cannot read property ‘fire’ of null]
    Failing descriptor: {c:dynamicRowItem$controller$AddNewRow}

  • I am not able to assign the text box value to the contact record, can you please let me know the reason for that.

    • are you using the same code ? Lightning Component and JavaScript are case sensitive, make sure your Object API field Names are correct

  • Hay

    This Page has an error .You might just need to refresh it.Like.

     

    Error in $A.getCallback() [Cannot read property ‘FirstName’ of null]

    How can I use look up and currency field.

     

     

  • Hello,

    I’m very new to SFD and love, love, love your posts here. I am using your above example (modifying a little to make it my own) and made two components, the one component works like a dream but the other throws an error when I try to delete a row. The only difference is the one has an  ui:inputSelect field and thats the field that’s causing the error. It actually does delete the row but I always get this error.  Again I don’t have this problem on my other component that is identical to this other than it does not have an inputSelect control. Any thoughts?

    Error:

    Uncaught Action failed: ui:inputSelect$controller$valueChange [Cannot read property ‘inputselect field’ of undefined]
    Callback failed: apex://FormController/ACTION$deleteLineItem

    Thanks again for sharing your knowledge and helping us learn.

  • Thanks for the code. Can you just help me with below requirement :

    I want to show this dynamic row adding with 3 fields  inside another parent component and save the 3 fields value on that parent object. How to achieve this functionality? Need help, to get a way to do it.

  • Hi,

    I’m getting below error . Please help. I’m using this on custom object and field is picklist which is throwing error.

     

    This page has an error. You might just need to refresh it. Action failed: ui:inputSelect$controller$valueChange [Cannot read property ‘Company__c’ of undefined] Callback failed: apex://addDeleteController/ACTION$saveCars Failing descriptor: {ui:inputSelect$controller$valueChange}

  • Ive used this way of iterating over a component to add multiple rows but only one rows gets added during initialization. Consequent actions to add rows prove futile.

  • This page has an error. You might just need to refresh it. Unknown controller action ‘AddNewRow’ Failing descriptor: {markup://c:dynamicRowItem}

  • This worked out great! Where can I find information on adding a picklist to the table and using with the controllers?

  • How do we insert these multiple contacts with Account?
    Basically, how do we insert records with lookup field(using recordEditForm)

  • Is there any way to put delete functionality in parent component to delete selected child instance with check box , I am trying to put a button in parent and when I click that button I should delete the selected rows.

  • Hi, thank you very much for this.

    I was wondering, could you help with providing the code so that this would be inside another component, and therefore all the multiple records would be inserted as related to that object.

    Thank you in advance!

  • Hi,

    When user click on + (add) icon new row adding but I need here some functionality after added new row cursor focus need to be on “Firstname” textbox on newly created row. How to do, can you explain and send me sample code.

    Thanks,

    Anji

  • Thank you so much  for share your costly time with  this blogs . And this is very helpful Requirement like when user click on add function icon new row adding ..Great work Heads off you and your Team for help .

     

  • Thanks for this, How can I make it work with <lightning:inputField ****/> or <force: inputField***>, I need to use one of these so the input fields respect the field types of an object, for an example a lookup field

  • Hi,

    How to limit the row adding, i have the requirement max add rows 20.

    Please let me know where should i add the code

  • Hi,

    Please let me know how to control the add row count

    we have the requirement,  should allow only 20 mix add rows.

    Please let me know

  • Hello i am facing problem in saving records, i am unbale to save. please let me know if you have solutions.

  • Hello ,
    i am facing problem in saving records, i am unbale to save. please let me know if you have solutions.

  • Hi, This is a good Post, we have a requirement to make this component more dyanamic,

    depending on parameters we have to create dynamic table and it should have dynamic rows like you already done.

    Can you help me in this?

    Thanks,

    Jyoti

  • Hi,

    This is really a good post.

    I want more dynamic functionality in it.

    Table should get displayed depending on my configurations and it will have such dyanamic rows as well.

    can we have solution for it?

    Thanks.

  • Seems to work great; however, echoing Azar’s question from July 2018, how can we set the AccountId on the newly created Contacts? This seems like a critical element to this functionality.

    I figured out how to update the Parent Component to run in a flow and to include an AccountId variable using the Design element, and then I can pass in an Account id from the flow running from the Account page, but how can I take that value I assign to the Parent Component and pass it through to the Contacts being created in the Child Component?

  • Hello ,
    Great post!
    I’m facing a problem in saving records though – nothing happening on save – please let me know if you have solution for this.
    Thanks

Leave a Reply