Dynamic Modal with Create, Update records

To create a dynamic modal using Lightning Web Components (LWC) with slots for creating and updating records, you’ll need to set up two components: the parent component that manages the modal and the child component that serves as the modal itself. Slots will be used to allow for dynamic content insertion into the modal.

Step 1: Create the Modal Component

  1. Component Structure:

    • dynamicModal
      • dynamicModal.html
      • dynamicModal.js
      • dynamicModal.js-meta.xml
      • dynamicModal.css (optional)
  2. dynamicModal.html:

html

<template>

<template if:true={isOpen}>
<section role="dialog" tabindex="-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<header class="slds-modal__header">
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={closeModal}>
<lightning-icon icon-name="utility:close" alternative-text="close" size="small"></lightning-icon>
<span class="slds-assistive-text">Close</span>
</button>
<h2 class="slds-text-heading_medium">{modalTitle}</h2>
</header>
<div class="slds-modal__content slds-p-around_medium">
<slot name="content"></slot>
</div>
<footer class="slds-modal__footer">
<lightning-button variant="neutral" label="Cancel" onclick={closeModal}></lightning-button>
<lightning-button variant="brand" label="Save" onclick={handleSave}></lightning-button>
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</template>
</template>
  1. dynamicModal.js:

javascript

import { LightningElement, api } from 'lwc';

export default class DynamicModal extends LightningElement {
@api isOpen = false;
@api modalTitle = 'Manage Record';

closeModal() {
this.isOpen = false;
this.dispatchEvent(new CustomEvent('close'));
}

handleSave() {
this.dispatchEvent(new CustomEvent('save'));
}
}

  1. dynamicModal.js-meta.xml:

xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>56.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
  1. dynamicModal.css: (optional for styling)

css

.slds-modal__header {

background: #f4f6f9;
}

.slds-modal__footer {
background: #f4f6f9;
}

Step 2: Create the Parent Component

  1. Component Structure:

    • parentComponent
      • parentComponent.html
      • parentComponent.js
      • parentComponent.js-meta.xml
      • parentComponent.css (optional)
  2. parentComponent.html:

html

<template>
<lightning-card title="Dynamic Table">
<div class="slds-m-around_medium">
<lightning-button variant="brand" label="New Record" onclick={handleNew}></lightning-button>
<lightning-datatable
key-field="id"
data={data}
columns={columns}
onrowaction={handleRowAction}
>
</lightning-datatable>
</div>
</lightning-card>

<c-dynamic-modal
is-open={isModalOpen}
modal-title={modalTitle}
onclose={handleCloseModal}
onsave={handleSaveModal}
>

<div slot="content">
<lightning-record-edit-form
object-api-name={objectApiName}
record-id={recordId}
onsuccess={handleSuccess}
onerror={handleError}
>

<lightning-messages></lightning-messages>
<template for:each={fields} for:item="field">
<lightning-input-field key={field.fieldPath} field-name={field.fieldPath}></lightning-input-field>
</template>
</lightning-record-edit-form>
</div>
</c-dynamic-modal>
</template>

  1. parentComponent.js:

javascript

import { LightningElement, wire, track } from 'lwc';
import getRecords from '@salesforce/apex/RecordController.getRecords';

const COLUMNS = [
{ label: 'Name', fieldName: 'Name' },
{ label: 'Status', fieldName: 'Status__c' },
{
type: 'button-icon',
typeAttributes: {
iconName: 'utility:edit',
title: 'Edit',
variant: 'border-filled',
alternativeText: 'Edit'
}
}
];

export default class ParentComponent extends LightningElement {
@track data = [];
@track columns = COLUMNS;
@track isModalOpen = false;
@track recordId = null;
@track objectApiName = 'CustomObject__c'; // Adjust this as necessary
@track fields = [
{ fieldPath: 'Name' },
{ fieldPath: 'Status__c' }
]; // Adjust this as necessary
@track modalTitle = 'Manage Record';

@wire(getRecords)
wiredRecords({ error, data }) {
if (data) {
this.data = data;
} else if (error) {
this.showToast('Error', 'Error fetching records', 'error');
}
}

handleNew() {
this.recordId = null;
this.modalTitle = 'New Record';
this.isModalOpen = true;
}

handleRowAction(event) {
const actionName = event.detail.action.name;
const row = event.detail.row;

switch (actionName) {
case 'edit':
this.editRecord(row);
break;
default:
break;
}
}

editRecord(row) {
this.recordId = row.Id;
this.modalTitle = 'Edit Record';
this.isModalOpen = true;
}

handleCloseModal() {
this.isModalOpen = false;
// Refresh the table data after closing the modal
return refreshApex(this.wiredRecords);
}

handleSaveModal() {
// Save action handled by lightning-record-edit-form, so just close the modal
this.isModalOpen = false;
}

handleSuccess() {
this.showToast('Success', 'Record saved successfully', 'success');
this.handleCloseModal();
}

handleError() {
this.showToast('Error', 'Error saving record', 'error');
}

showToast(title, message, variant) {
const event = new ShowToastEvent({
title,
message,
variant
});
this.dispatchEvent(event);
}
}

  1. parentComponent.js-meta.xml:

xml

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

Step 3: Create Apex Controller

  1. RecordController.cls:

apex

public with sharing class RecordController {
@AuraEnabled(cacheable=true)
public static List<CustomObject__c> getRecords() {
return [SELECT Id, Name, Status__c FROM CustomObject__c];
}
}

Step 4: Deploy and Use the Components

  1. Deploy the Components:

    • Use SFDX or your preferred method to deploy the LWC files and the Apex controller to your Salesforce org.
  2. Use the Parent Component in a Lightning App/Page:

    • Go to the Lightning App Builder and drag the parentComponent component onto the page.
    • Configure the component’s objectApiName, fields, and other properties as needed.

By following these steps, you can create a dynamic table in Salesforce that allows users to create and update records through a modal. The parent component dynamically interacts with the modal, passing the necessary configuration and handling user actions. Adjust the component and logic as per your specific requirements.

Leave A Comment

All fields marked with an asterisk (*) are required