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
Major1507Major1507 

Hi, I have created a lightning component in which i'm adding rows usinf the ADD button and deleting the roes using DELETE button. I want to know how can i limit the addition of new rows to 10 rows only and after that the ADD button should get disabled.

Best Answer chosen by Major1507
Ashif KhanAshif Khan
Hi Kuldeep,

demo.app
 
<aura:application extends="force:slds">
   <c:dynamicRow />
  
</aura:application>




dynamicRow.cmp 
<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>
   </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>
            
            <aura:iteration items="{!v.contactList}" var="ContactInstance" indexVar="rowIndex">
          <tr class="slds-text-title_caps">
        <td> 
            {!rowIndex + 1}
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!ContactInstance.FirstName}"/>
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!ContactInstance.LastName}"/>
        </td>
        <td>
            <ui:inputPhone class="slds-input" value="{!ContactInstance.Phone}"/>
        </td>
        <td>
            <aura:if isTrue="{!rowIndex == 0}">
                <aura:if isTrue="{!lessthanorequal(v.contactList.length,10)}">
                  <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">
                    <lightning:buttonIcon size='large' iconName="utility:add" variant="bare"  alternativeText="Add" disabled='true'  />  
                    </aura:set>
                </aura:if>   
           
              <aura:set attribute="else">
                  <a onclick="{!c.removeDeletedRow}" data-value="{!rowIndex}">
                   <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: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>


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 ctarget = event.currentTarget;
        var index = ctarget.dataset.value;
        // 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);
    },
})

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", []);      
        component.set("v.contactList", RowItemList);
        
          //      alert(JSON.stringify(component.get("v.contactList")));
        
    },
    // 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;
    },
})

Same functionality in the single component.

I hope this Will help you please close the question mark as Best.

Regards 
Ashif

All Answers

Major1507Major1507
I'm sorry for wrong question, i have actually used Lightning:icon instead of button

the disabled attribute does not work with lightning:icon

i need to disable the icon.
Thank you
Major1507Major1507
This is my code:

<aura:if isTrue="{!v.rowIndex == index}">
                <a onclick="{!c.AddNewRow}">
                  <lightning:buttonicon iconName="utility:add" class="slds-icon slds-icon_small" size="small" alternativeText="add" disabled='{!v.rowIndex == 8}'/>
                  <span class="slds-assistive-text">Add Icon</span>
                </a>
                 
            </aura:if>

default = 'true' is working fine now, but when i give a value for row index, it doesnt work
Major1507Major1507
Its still not working
Major1507Major1507
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="DeleteRowEvt" type="c:DeleteRowEvt"/> 
    <aura:registerEvent name="AddRowEvt" type="c:AddNewRowEvt"/> 


<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>

Child Controller .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();
    }, 
  
})

Parent Component
<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[]"/> 


<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>

Parent Controller .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);
    },

 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);
    },
})

Parent Helper 
({
    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);
    }

 
Major1507Major1507
Thanks a lot for the help, but its still not limiting to 10 rows.
It keeps on adding indefinitely.
Ashif KhanAshif Khan
I am sharing a sfdcmonkey blog with you i updated it . It will add only 10 rows as per your requirement. Just run it 

AddNewRowEvt.evt
<aura:event type="COMPONENT" description="Use For Add New Row"></aura:event>

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

dynamicRowItem.cmp
<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"/>
     <aura:attribute name="contactList" type="Contact[]"/> 
    <!-- 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}">
                <lightning:buttonIcon size='large' iconName="utility:add" variant="bare" onclick="{! c.AddNewRow }" alternativeText="Add" disabled='{!v.contactList.length>=10}'  />
             
              <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>

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();
    }, 
  
})


addDeleteController.apxc
 
public with sharing class addDeleteController {
   @AuraEnabled
    public static void saveContacts(List<Contact> ListContact){
        Insert ListContact;
    }
}

dynamicRow.cmp
 
<!--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}" contactList='{!v.contactList}' />
            </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>

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);
    },
})

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;
    },
})

demo.app
 
<aura:application extends="force:slds">
    <c:dynamicRow/>
<!-- here c: is org. default namespace prefix-->
</aura:application>

User-added image

This is the complete code which is working fine as you expecting in my dev org
 
Major1507Major1507
Can this be achieved by only using parent component?
If yes then please let me know.

Thanks
Ashif KhanAshif Khan
Hi Kuldeep,

demo.app
 
<aura:application extends="force:slds">
   <c:dynamicRow />
  
</aura:application>




dynamicRow.cmp 
<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>
   </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>
            
            <aura:iteration items="{!v.contactList}" var="ContactInstance" indexVar="rowIndex">
          <tr class="slds-text-title_caps">
        <td> 
            {!rowIndex + 1}
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!ContactInstance.FirstName}"/>
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!ContactInstance.LastName}"/>
        </td>
        <td>
            <ui:inputPhone class="slds-input" value="{!ContactInstance.Phone}"/>
        </td>
        <td>
            <aura:if isTrue="{!rowIndex == 0}">
                <aura:if isTrue="{!lessthanorequal(v.contactList.length,10)}">
                  <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">
                    <lightning:buttonIcon size='large' iconName="utility:add" variant="bare"  alternativeText="Add" disabled='true'  />  
                    </aura:set>
                </aura:if>   
           
              <aura:set attribute="else">
                  <a onclick="{!c.removeDeletedRow}" data-value="{!rowIndex}">
                   <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: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>


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 ctarget = event.currentTarget;
        var index = ctarget.dataset.value;
        // 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);
    },
})

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", []);      
        component.set("v.contactList", RowItemList);
        
          //      alert(JSON.stringify(component.get("v.contactList")));
        
    },
    // 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;
    },
})

Same functionality in the single component.

I hope this Will help you please close the question mark as Best.

Regards 
Ashif
This was selected as the best answer
Francisco Corona 7Francisco Corona 7
Hello, I am also trying to acheieve the above but cannot get it to work. Below you will see the component, controller and helper. 

Component:

<aura:component controller="ClosePlanController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" access="global" >
    
    <!-- attributes -->
    <aura:attribute name="data" type="Object"/>
    <aura:attribute name="columns" type="List"/>
    <aura:attribute name="errors" type="Object" default="[]"/>
    <aura:attribute name="draftValues" type="Object" default="[]"/>

    <!-- Imports -->
   <!-- <aura:import library="lightningcomponentdemo:mockdataFaker" property="mockdataLibrary"/>-->

    <!-- handlers-->
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>

    

    <!-- the container element determine the height of the datatable -->
    <div style="height: 300px">
        <lightning:datatable
            columns="{! v.columns }"
            data="{! v.data }"
            keyField="id"
            errors="{! v.errors }"
            draftValues="{! v.draftValues }"
            onsave="{! c.handleSaveEdition }"
        />
    </div>


</aura:component>


Controller:

({
    init: function (cmp,helper) {
        cmp.set('v.columns', [
            {label: 'Proposed Activity', fieldName: 'Proposed_Activity__c ', type: 'text', editable: true, typeAttributes: { required: true }},
            {
                label: 'Target Date', fieldName: 'Target_Date__c ', type: 'date', editable: true,
                typeAttributes: {
                    year: 'numeric',
                    month: 'short',
                    day: 'numeric',
                    hour: '2-digit',
                    minute: '2-digit'
                }
            },
            {label: 'Comments', fieldName: 'Comments__c', type: 'text', editable: true }
            
        ]);
        helper.getData(cmp);
        helper.initServer().then($A.getCallback(function () {
            helper.fetchData(cmp)
        }));
    }
   /* handleSaveEdition: function (cmp, event, helper) {
        var draftValues = event.getParam('draftValues');

        helper.saveEdition(cmp, draftValues);
    },
    handleCancelEdition: function (cmp) {
        // do nothing for now...
    }*/
})


Helper:

({
    getData : function(cmp) {
        var action = cmp.get('c.getClosePlans');
        action.setCallback(this, $A.getCallback(function (response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                cmp.set('v.mydata', response.getReturnValue());
            } else if (state === "ERROR") {
                var errors = response.getError();
                console.error(errors);
            }
        }));
        $A.enqueueAction(action);
    }
})


They all save, but we get the following error message when we are trying to paste it on the lightning record page.


User-added image

Can you please help. We are trying to create a component that will allow us to create multiple records from a single screen, similar to Manage Contact Roles.

Francisco
Francisco Corona 7Francisco Corona 7
Hello,

I got the component to work, but our next task is to be able to show what we insert back in the same component. In essense, be able to see our inserted records within the same component. Similar to how the "Manage Contact Roles" works in lightning. 

Thanks,

Francisco
Salesforce CodesSalesforce Codes
This be the best answer for the scenario
Dynamic Add or Remove Rows using Lightning Component
User-added image
http://salesforcecodes.com/dynamic-add-or-remove-rows-using-lightning-component/ (http://salesforcecodes.com/dynamic-add-or-remove-rows-using-lightning-component/" target="_blank)


 Here we have shown Inserting multiple records using Add Or Remove Row functionality in Lightning Component.
If at all Account Name is empty, error message will be displayed in alert message.​​​​​​​