Add/Remove Rows in Data table in LWC Salesforce

by Rijwan Mohmmed

Hello, Friends today we will learn to add new rows /remove and perform DML operations. Add/Remove Rows in Data table in LWC Salesforce

Key Highlights

  1. We create a LWC quick action on Account record
  2. Popup will display any existing contacts
  3. Ability to add new rows to add new contacts
  4. Ability to update existing contacts
  5. Ability to delete contacts (A delete icon in front of every row)
  6. Clicking on save button will invoke an apex method to Create, Update and Delete contacts in a single operation.
  7.  Display spinner on save operation
  8. Error handling

We will add/remove Rows in the Data table in LWC Salesforce in this video.

Check out this: Expand/Collapse Section in LWC

Lets start our code

AccountContactTable.Html :

    <lightning-quick-action-panel header="Manage Contacts">
        <div class="slds-p-around_none slds-m-top_x-small slds-m-bottom_medium slds-m-horizontal_none modalBodyy">
             <template if:true={isLoading}>
                <lightning-spinner alternative-text="Loading" size="medium" class="spinnerClass"></lightning-spinner>
                 <lightning-button label="Add Row" slot="actions" icon-name="utility:add" onclick={addRow}></lightning-button>
                <div class="slds-m-around_medium">
                    <table class="slds-table slds-table_cell-buffer slds-table_bordered" aria-labelledby="element-with-table-label other-element-with-table-label">
                            <tr class="slds-line-height_reset">
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="First Name">First Name</div>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Last Name">Last Name</div>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Email">Email</div>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Stage">Action</div>
                            <template for:each={records} for:item="obj">
                                <tr class="inputRows" key={obj.Id}>
                                    <th data-label="Opportunity Name" scope="row">
                                        <lightning-input type="text" class="fields" variant="label-hidden" label="First Name" name="FirstName" value={obj.FirstName} data-id={obj.Id} onchange={updateValues}></lightning-input>
                                    <td data-label="Account Name">
                                        <lightning-input type="text" class="fields" variant="label-hidden" label="Last Name" name="LastName" value={obj.LastName} data-id={obj.Id} onchange={updateValues}></lightning-input>
                                    <td data-label="Close Date">
                                       <lightning-input type="text" class="fields" variant="label-hidden" label="Email" name="Email" value={obj.Email} data-id={obj.Id} onchange={updateValues}></lightning-input>
                                    <td data-label="Prospecting">
                                        <lightning-button-icon icon-name="action:delete"  alternative-text="Delete" title="Delete" data-id={obj.Id} onclick={handleDeleteAction}></lightning-button-icon>
        <div slot="footer">
            <lightning-button variant="neutral" label="Cancel" onclick={closeAction}></lightning-button> &nbsp;
            <lightning-button variant="brand" label="Save" onclick={handleSaveAction} disabled={isDisable}></lightning-button>

AccountContactTable.Js :

import { LightningElement, api, track, wire } from 'lwc';
import { CloseActionScreenEvent } from 'lightning/actions';
import { ShowToastEvent } from 'lightning/platformShowToastEvent'
import fetchContacts from '@salesforce/apex/ContactController.fetchContacts';
import dmlOnContacts from '@salesforce/apex/ContactController.dmlOnContacts';
import { refreshApex } from '@salesforce/apex';

export default class AccountContactTable extends LightningElement {
    @api recordId;
    @track isLoading = true;
    @track records;
    @track deleteConatctIds = '';

    //to close quick action
        this.dispatchEvent(new CloseActionScreenEvent());

    //to add row
    addRow() {
        let randomId = Math.random() * 16;
        let myNewElement = {Email: "", FirstName: "", Id: randomId, LastName: "", AccountId: this.recordId};
        this.records = [...this.records, myNewElement];

    get isDisable(){
        return (this.isLoading || ( == 0 && this.records.length == 0));

    //show/hide spinner
    handleIsLoading(isLoading) {
        this.isLoading = isLoading;

    //update table row values in list
        var foundelement = this.records.find(ele => ele.Id ==;
        if( === 'FirstName'){
            foundelement.FirstName =;
        } else if( === 'LastName'){
            foundelement.LastName =;
        } else if( === 'Email'){
            foundelement.Email =;

    //handle save and process dml 

        if(this.deleteConatctIds !== ''){
            this.deleteConatctIds = this.deleteConatctIds.substring(1);

        this.records.forEach(res =>{
                res.Id = null;
        dmlOnContacts({data: this.records, removeContactIds : this.deleteConatctIds})
        .then( result => {
            this.showToast('Success', result, 'Success', 'dismissable');
        }).catch( error => {
            this.showToast('Error updating or refreshing records', error.body.message, 'Error', 'dismissable');

    //remove records from table
            this.deleteConatctIds = this.deleteConatctIds + ',' +;
        this.records.splice(this.records.findIndex(row => row.Id ===, 1);

    //fetch account contact records
    @wire(fetchContacts, {recordId : '$recordId'})  
    wiredContact(result) {
        this.wiredRecords = result; // track the provisioned value
        const { data, error } = result;

        if(data) {
            this.records = JSON.parse(JSON.stringify(data));
            this.error = undefined;
        } else if(error) {
            this.error = error;
            this.records = undefined;

    showToast(title, message, variant, mode) {
        const event = new ShowToastEvent({
            title: title,
            message: message,
            variant: variant,
            mode: mode

    updateRecordView() {
       setTimeout(() => {
       }, 3000); 

AccountContactTable.css :

.modalBodyy {
    position: relative;

accountContactTable.js-meta.xml :

<?xml version="1.0"?>
<LightningComponentBundle xmlns="">
        <targetConfig targets="lightning__RecordAction">

ContactController.cls :

public class ContactController {
    @AuraEnabled( cacheable = true )
    public static List<Contact> fetchContacts(String recordId) {
        return [SELECT Id, AccountId, FirstName, LastName, Email FROM Contact WHERE AccountId =:recordId LIMIT 100];

    public static string dmlOnContacts(Object data, String removeContactIds) {
        List<Contact> updateContact = (List<Contact>) JSON.deserialize(JSON.serialize(data), List<Contact>.class);
        List<Contact> deleteContact = new List<Contact>();

            List<Id> contactIds = removeContactIds.split(',');
            deleteContact = [SELECT Id FROM Contact WHERE Id IN :contactIds];

        try {
            if(updateContact != null && !updateContact.isEmpty()){
                upsert updateContact;

            if(deleteContact != null && !deleteContact.isEmpty()){    
                delete deleteContact;
            return 'Success: Contact(s) upsert/delete successfully';
        catch (Exception e) {
            String errorMsg = 'The following exception has occurred: ' + e.getMessage();
            throw new AuraHandledException(ErrorMsg);
       // return '';

You may also like


kamila May 7, 2023 - 8:14 pm

Hello, i create a table with custom field and it´s not working, dont update fields. Can u help me?

Rijwan Mohmmed May 8, 2023 - 3:18 am

which object you are using of update.


Leave a Comment