Dynamically adding and deleting Rows in Salesforce Lightning Web Component(LWC)

Dynamically adding and deleting Rows in Salesforce Lightning Web Component(LWC)

Apex Class:

public class DynamicRowsController {
    
    @AuraEnabled
    public static String updateAccts( List < Account > listAccts ) {
        
        try {
           
            insert listAccts;
            return 'Successful';
            
        } catch ( Exception e ) {
            
            throw new AuraHandledException( e.getMessage() );
            
        }
        
    }

}

Lightning Web Component:

HTML:

<template>
    <lightning-card>
        <table class="slds-table">
            <tr>
                <th>Name</th>
                <th>Industry</th>
                <th>Active Date</th>
                <th>Is Active?</th>
                <th>Type</th>
                <th>Description</th>
                <th>Action</th>
            </tr>
            <template iterator:it={accounts}>
                <tr key={it.value.Name}>
                    <td>
                        <lightning-input
                            type="text"
                            label="Account Name"
                            value={it.value.Name}
                            data-record-id={it.index}
                            onchange={handleChange}
                            variant="label-hidden">
                        </lightning-input>
                    </td>
                    <td>
                        <lightning-combobox
                            key={it.value.Name}
                            value={it.value.Industry}
                            options={industryOptions}
                            data-record-id={it.index}
                            onchange={handleChange}
                            label="Industry"
                            variant="label-hidden">
                        </lightning-combobox>
                    </td>
                    <td><lightning-input
                            type="date" 
                            label="Active Date"
                            value={it.value.Active_Date__c}
                            data-record-id={it.index}
                            onchange={handleChange}
                            variant="label-hidden">
                        </lightning-input>
                        </td>
                    <td><lightning-input
                            type="checkbox"
                            label="Is Active?"
                            value={it.value.Is_Active__c}
                            data-record-id={it.index}
                            onchange={handleChange}
                            variant="label-hidden">
                        </lightning-input>
                    </td>   
                    <td>                 
                        <lightning-combobox
                            key={it.value.Name}
                            value={it.value.Type}
                            data-record-id={it.index}
                            options={typeOptions}
                            onchange={handleChange}
                            label="Type">
                        </lightning-combobox>
                    </td>
                    <td><lightning-input
                            type="text"
                            label="Description"
                            value={it.value.Description}
                            data-record-id={it.index}
                            onchange={handleChange}>
                        </lightning-input>
                    </td>
                    <td><lightning-button
                            variant="base"
                            label="Delete"
                            onclick={deleteRow}
                            data-record-id={it.index}>
                        </lightning-button>
                    </td>
                </tr>
            </template>
            <tr>
                <td><lightning-button label="Add Row" onclick={addRow}></lightning-button></td>
            </tr>
        </table>
        <p slot="footer">
            <lightning-button variant="brand" label="Save Records" onclick={saveAccounts}></lightning-button>
        </p>
    </lightning-card>
</template>

JavaScript:

import { LightningElement, wire } from 'lwc';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
import TYPE_FIELD from '@salesforce/schema/Account.Type';
import { getPicklistValues, getObjectInfo } from 'lightning/uiObjectInfoApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import updateAccts from '@salesforce/apex/DynamicRowsController.updateAccts';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class DynamicRows extends LightningElement {

    accounts;
    error;
    typeOptions;
    industryOptions;

    connectedCallback() {

        this.accounts = [ {
            'Name' : null,
            'Industry' : null,
            'Active_Date__c' : null,
            'Is_Active__c' : false,
            'Type' : null,
            'Description' : null
        } ];

    }

    @wire( getObjectInfo, { objectApiName: ACCOUNT_OBJECT } )
    objectInfo;

    @wire( getPicklistValues, { recordTypeId: '$objectInfo.data.defaultRecordTypeId', fieldApiName: INDUSTRY_FIELD } )
    getIndustryValues( { error, data } ) {

        if ( data ) {
                            
            this.industryOptions = data.values.map( objPL => {
                return {
                    label: `${objPL.label}`,
                    value: `${objPL.value}`
                };
            });

        } else if ( error ) {

            console.error( JSON.stringify( error ) );

        }

    }

    @wire( getPicklistValues, { recordTypeId: '$objectInfo.data.defaultRecordTypeId', fieldApiName: TYPE_FIELD } )
    getTypeValues( { error, data } ) {

        if ( data ) {
                            
            this.typeOptions = data.values.map( objPL => {
                return {
                    label: `${objPL.label}`,
                    value: `${objPL.value}`
                };
            });

        } else if ( error ) {

            console.error( JSON.stringify( error ) );

        }

    }

    addRow() {

        let newEntry = {
            'Name' : null,
            'Industry' : null,
            'Active_Date__c' : null,
            'Is_Active__c' : false,
            'Type' : null,
            'Description' : null
        };

        if ( this.accounts ) {

            this.accounts = [ ...this.accounts, newEntry ];

        } else {

            this.accounts = [ newEntry ];

        }

    }

    deleteRow( event ) {

        let strIndex = event.target.dataset.recordId;
        let tempAccounts = this.accounts;
        tempAccounts.splice( strIndex, 1 );
        console.log( 'Temp Accounts are ' + JSON.stringify( tempAccounts ) );
        this.accounts = JSON.parse( JSON.stringify( tempAccounts ) );

    }

    handleChange( event ) {

        let recs =  this.accounts;
        let value = event.target.value;
        let label = event.target.label;
        let name;

        switch( label ) {

            case 'Account Name':
                name = 'Name';
                break;

            case 'Industry':
                name = 'Industry';
                break;

            case 'Active Date':
                name = 'Active_Date__c';
                break;

            case 'Is Active?':
                name = 'Is_Active__c';
                value = event.target.checked;
                break;

            case 'Type':
                name = 'Type';
                break;

            case 'Description':
                name = 'Description';
                break;

        }

        console.log( label + ' - ' + value );
        let strIndex = event.target.dataset.recordId;
        console.log( 'Index is ' + strIndex );
        let rec = recs[ strIndex ];
        rec[ name ] = value;
        recs[ strIndex ] = rec;
        console.log( 'Temp Accounts are ' + JSON.stringify( recs ) );
        this.accounts = JSON.parse( JSON.stringify( this.accounts ) );

    }

    saveAccounts() {

        console.log( 'Temp Accounts are ' + JSON.stringify( this.accounts ) );

        updateAccts( { listAccts : this.accounts } )
        .then( result => {

            console.log( 'Result ' + JSON.stringify( result ) );
            let message;
            let variant;

            if ( result === 'Successful' ) {

                message = 'Successfully Processed!';
                variant = 'success';

            } else {

                message = 'Some error occured. Please reach out to your Salesforce Admin for help!';
                variant = 'error';
                
            }

            const toastEvent = new ShowToastEvent( {

                title: 'Account creation',
                message: message,
                variant: variant

            } );
            this.dispatchEvent( toastEvent );

        } )
        .catch( error => {

            console.log( 'Error ' + JSON.stringify( error ) );
            
        } );

    }

}

JS-meta.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>

Output:

Leave a Reply