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
-
Component Structure:
dynamicModal
dynamicModal.html
dynamicModal.js
dynamicModal.js-meta.xml
dynamicModal.css
(optional)
-
dynamicModal.html:
html
<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>
- 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'));
}
}
- 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>
- dynamicModal.css: (optional for styling)
css
background: #f4f6f9;
}
.slds-modal__footer {
background: #f4f6f9;
}
Step 2: Create the Parent Component
-
Component Structure:
parentComponent
parentComponent.html
parentComponent.js
parentComponent.js-meta.xml
parentComponent.css
(optional)
-
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>
- 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);
}
}
- 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
- 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
-
Deploy the Components:
- Use SFDX or your preferred method to deploy the LWC files and the Apex controller to your Salesforce org.
-
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.
- Go to the Lightning App Builder and drag the
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.