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
Maharajan CMaharajan C 

Add/Remove Records using Lightning Web Components

Hi All,

Add/Remove Records using LWC.

If any one want to create Add/Remove multiple records in lightning web component dynamically then please refer this post. 

Features:
1. Add rows using plus( + ) button.
2. Dynamic Add/Remove record row.
3. Proper Serial Number in table. For each index starts from 1.
4. Clear All Feature.
5. Save button label change button.
6. Toast Message after record succesfully inserted.

Refer the code in below post...

Like this Post if it's helps to any one !!!

Thanks,
Maharajan.C
Maharajan CMaharajan C
I am using 2 LWC component to this development.

Component 1:

addDeleteRowDynamicComponent.html
 
<template>
        <lightning-card title="Create Accounts" icon-name="standard:account">
        <lightning-button-icon icon-name="utility:add" slot="actions" onclick={addRow}></lightning-button-icon>
        <lightning-button 
            label={toggleSaveLabel} 
            icon-name="utility:save" 
            slot="actions"
            onclick={handleSave}>
        </lightning-button>
        <lightning-button 
            label="Clear All" 
            icon-name="utility:clear" 
            slot="actions"
            onclick={accountTempRecords}>
        </lightning-button>


        <table class="slds-table slds-table_cell-buffer slds-table_bordered">
            <thead>
                <tr class="">
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="Name">S.No</div>
                    </th>
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="Name">Name</div>
                    </th>
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="First Name">NumberOfEmployees</div>
                    </th>
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="Last Name">Phone</div>
                    </th>
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="Phone">Website</div>
                    </th>
                    <th class="slds-size_3-of-10" scope="col">
                        <div class="slds-truncate" title="Phone">Action</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <template for:each = {accRecords} for:item = "acc" for:index="indexVar">
                    <tr key={acc.key} class="slds-hint-parent">
                        <td class="slds-size_3-of-10" data-label="Prospecting">
                            <div  title="Prospecting">
                                <div class="slds-text-heading_small slds-text-align_center">
                                    <c-serial-number-comp index={indexVar}></c-serial-number-comp>
                                </div>
                            </div>
                        </td>
                        <td class="slds-size_3-of-10" data-label="Prospecting">
                            <div  title="Prospecting">
                                <lightning-input key={acc.key} data-id={acc.key} name="input1" label="Name" value={acc.Name} variant="label-hidden" onchange={handleNameChange}></lightning-input>
                            </div>
                        </td>
                        <td class="slds-size_3-of-10" data-label="Prospecting">
                            <div  title="Prospecting">
                                <lightning-input key={acc.key} data-id={acc.key} name="input1" label="NumberOfEmployees" value={acc.NumberOfEmployees} variant="label-hidden" onchange={handleEmpChange}></lightning-input>
                            </div>
                        </td>
                        <td class="slds-size_3-of-10" data-label="Prospecting">
                            <div  title="Prospecting">
                                <lightning-input key={acc.key} data-id={acc.key} name="input1" label="Phone" value={acc.Phone} variant="label-hidden" onchange={handlePhoneChange}></lightning-input>
                            </div>
                        </td>
                        <td class="slds-size_3-of-10" data-label="Prospecting">
                            <div  title="Prospecting">
                                <lightning-input key={acc.key} data-id={acc.key} name="input1" label="Website" value={acc.Website} variant="label-hidden" onchange={handleWebsiteChange}></lightning-input>
                            </div>
                        </td>
                        <td class="slds-size_1-of-10" data-label="Prospecting">
                            <a name={indexVar} data-id={acc.key} onclick={removeRow}>
                                    <lightning-icon icon-name="utility:delete" alternative-text="delete"  size="small"></lightning-icon>
                            </a>
                        </td>
                    </tr>
                </template>
            </tbody>
        </table>

    </lightning-card>
</template>

addDeleteRowDynamicComponent.js
 
import { LightningElement,track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import insertAccounts from '@salesforce/apex/addDeleteRowDynamicComponnetClass.insertAccounts';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import Phone_FIELD from '@salesforce/schema/Account.Phone';
import Employee_FIELD from '@salesforce/schema/Account.NumberOfEmployees';
import Website_FIELD from '@salesforce/schema/Account.Website';

export default class AddDeleteRowDynamicComponent extends LightningElement {
    @track accRecord = {Name : NAME_FIELD,NumberOfEmployees : Employee_FIELD,Phone : Phone_FIELD,Website : Website_FIELD,key : Math.random().toString(36).substring(2, 15)};
    @track accRecords = [];
    toggleSaveLabel = 'Save';
    NumberOfEmployees

    connectedCallback(){
        console.log('  === connectedCallback === ');
        /*for(var i=0; i < 4 ; i++){
            this.accRecords.push({Name : NAME_FIELD,NumberOfEmployees : Employee_FIELD,Phone : Phone_FIELD,Website : Website_FIELD,key : Math.random().toString(36).substring(2, 15)});
        } */
        this.accountTempRecords();
    }
    
    accountTempRecords(){
        this.accRecords = [];
        for(var i=0; i < 4 ; i++){
            this.accRecords.push({Name : NAME_FIELD,NumberOfEmployees : Employee_FIELD,Phone : Phone_FIELD,Website : Website_FIELD,key : Math.random().toString(36).substring(2, 15)});
        }
    }

    addRow(){
        const len = this.accRecords.length;
        this.accRecords.push({Name : NAME_FIELD,NumberOfEmployees : Employee_FIELD,Phone : Phone_FIELD,Website : Website_FIELD,key : Math.random().toString(36).substring(2, 15)});
    }

    removeRow(event){
        const indexPos = event.currentTarget.name;
        let remList = [];
        remList = this.accRecords;
        remList.splice(indexPos,1);
        this.accRecords = remList;
    }

    handleNameChange(event){
        let foundelement = this.accRecords.find(ele => ele.key == event.target.dataset.id);
        foundelement.Name = event.target.value;
        this.accRecords = [...this.accRecords];
        //console.log(' ==> ' +  JSON.stringify(this.accRecords));
    }

    handleEmpChange(event){
        let foundelement = this.accRecords.find(ele => ele.key == event.target.dataset.id);
        foundelement.NumberOfEmployees = event.target.value;
        this.accRecords = [...this.accRecords];
        //console.log(' ==> ' +  JSON.stringify(this.accRecords));
    }

    handlePhoneChange(event){
        let foundelement = this.accRecords.find(ele => ele.key == event.target.dataset.id);
        foundelement.Phone = event.target.value;
        this.accRecords = [...this.accRecords];
        //console.log(' ==> ' +  JSON.stringify(this.accRecords));
    }

    handleWebsiteChange(event){
        let foundelement = this.accRecords.find(ele => ele.key == event.target.dataset.id);
        foundelement.Website = event.target.value;
        this.accRecords = [...this.accRecords];
        //console.log(' ==> ' +  JSON.stringify(this.accRecords));
    }

    handleSave(){
        this.toggleSaveLabel = 'Saving...'
        let toSaveList = this.accRecords.slice(0);;
        toSaveList.forEach((element, index) => {
            console.log( index + ' ==> ' + JSON.stringify(element.Name));
            let eleType = typeof element.Name;
            console.log( 'typeof ==> ' + eleType);
            if(element.Name === '' || eleType=='object'){
                toSaveList.splice(index);
            }
        });  
        console.log( ' Final Save ==> ' + JSON.stringify(toSaveList));

        insertAccounts({accList : toSaveList})
        .then(() => {
            this.toggleSaveLabel = 'Saved';
            console.log('Success Log');
            this.dispatchEvent(
                new ShowToastEvent({
                    title : 'Success',
                    message : `Records saved succesfully!`,
                    variant : 'success',
                }),
            )
            this.accountTempRecords();
            this.error = undefined;
        })
        .catch(error => {
            this.error = error;
            this.record = undefined;
            console.log("Error in Save call back:", this.error);
        })
        .finally(() => {
            setTimeout(() => {
                this.toggleSaveLabel = 'Save';
            }, 3000);
        });
    }
 
}

addDeleteRowDynamicComponent.js-meta.xml:
 
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets> 
     <target>lightning__AppPage</target>
     <target>lightning__RecordPage</target>
     <target>lightning__HomePage</target>
  </targets>
</LightningComponentBundle>

Component 2:  Using only for generating serial no:

serialNumberComp.html
 
<template>
    {position}. 
</template>

serialNumberComp.js
 
import { LightningElement,api } from 'lwc';

export default class SerialNumberComp extends LightningElement {
    @api index;
    get position() {
        return this.index + 1;
    }
}

Like this Post if it's helps to any one !!!

Thanks,
Maharajan.C
Maharajan CMaharajan C
Apex Class for this Component:
 
public class addDeleteRowDynamicComponnetClass {
    @AuraEnabled
    Public static string insertAccounts(List<Account> accList){
        system.debug(' insertAccounts ==> ');
        system.debug(' accList ==> ' + accList);
        String response = '';
        try{
            for(Account acc : accList){
               acc.NumberOfEmployees = Integer.valueOf(acc.NumberOfEmployees);
            }
            insert accList;
            response = 'SUCCESS';
        }
        catch(Exception ex){
            system.debug(' Ex ==> ' + ex.getMessage());
            response = ex.getMessage();
        }
        return response;
    }
}


Finan Output Will be like below:

User-added image


User-added image

User-added image


Thanks,
Maharajan.C​​​​​​​
Anil Bolisetty 2Anil Bolisetty 2
Just a small improvement rather than getting every value from handlechange events use queryselectorall it will reduce lot of code and makes it simple
gurram priyankagurram priyanka
delete and save action is not working for me
 
Packages PlanPackages Plan
I think it's good for us to use  This (https://packagesplan.pk/) .