Generic Record Edit Form — LWC
Problem Statement : Re-usable record edit form for creating and editing Single Record without making explicit server side Call .
lwcRecordEditForm.html
<template>
<template if:true={state.isLoading}>
<lightning-spinner variant=”brand” size=”large”></lightning-spinner>
</template>
<div class=’main-parent slds-scrollable_y’ style={props.outercss}>
<! — Header Section Begin →
<template if:true={props.header}>
<div class=”header”>
<a href=”#default” class=”logo”>
<lightning-icon icon-name=”standard:account”></lightning-icon>
{props.header}
</a>
<div class=”header-right” style=”margin-top:8px;”>
<lightning-button class=”slds-m-top_small saveBtn” onclick={onSubmit} label={props.btnlabel}
variant=”brand”>
</lightning-button>
<! — <a class=”active” onclick={onSubmit}>{props.btnlabel}</a> →
<! — <a href=”#contact”>Contact</a>
<a href=”#about”>About</a> →
</div>
</div>
</template>
<! — End Section Begin →
<! — Begin Editing a Record →
<template if:true={props.mode}>
<lightning-record-edit-form object-api-name={props.objectapiname} record-id={props.recordid}
onsubmit={onSubmit} onsuccess={onSuccess} onload={onLoad} onerror={onError}
record-type-id={props.recordtypeid}>
<! — <lightning-messages>
</lightning-messages> →
<lightning-layout>
<div class=”slds-grid slds-wrap”>
<template for:each={props.fieldSet} for:item=”field” for:index=”index”>
<div class={fieldWidth} key={field.apiname} style={props.innercss}>
<lightning-input-field field-name={field.apiname} disabled={field.disabled}
class=’slds-hide’>
</lightning-input-field>
</div>
</template>
</div>
</lightning-layout>
<div class=”slds-docked-form-footer”>
<lightning-button class=”slds-m-top_small saveBtn” onclick={onSubmit} label={props.btnlabel}
variant=”brand”>
</lightning-button>
</div>
</lightning-record-edit-form>
</template>
<! — BegEndin Editing a Record →
<! — Begin Creating a Record →
<template if:false={props.mode}>
<lightning-record-edit-form object-api-name={props.objectapiname} record-id={props.recordid}
record-type-id={props.recordtypeid} onsubmit={onSubmit} onsuccess={onSuccess} onload={onLoad}
onerror={onError}>
<! — <lightning-messages>
</lightning-messages> →
<lightning-layout>
<div class=”slds-grid slds-wrap”>
<template for:each={props.fieldSet} for:item=”field” for:index=”index”>
<div class={fieldWidth} key={field.apiname} style={props.innercss}>
<lightning-input-field field-name={field.apiname} disabled={field.disabled}
value={field.value} required={field.required}>
</lightning-input-field>
</div>
</template>
</div>
</lightning-layout>
<div class=”slds-docked-form-footer”>
<lightning-button class=”slds-m-top_small saveBtn” onclick={onSubmit} label={props.btnlabel}
variant=”brand”>
</lightning-button>
</div>
</lightning-record-edit-form>
</template>
<! — End Creating a Record →
</div>
</template>
lwcRecordEditForm.js
import { api, track } from ‘lwc’;
import LwcBaseElement from ‘c/lwcbaseelement’
import { NavigationMixin } from ‘lightning/navigation’;
import FORM_FACTOR from ‘@salesforce/client/formFactor’;
export default class LwcRecordEditForm extends NavigationMixin(LwcBaseElement) {
@api flexipageRegionWidth;
@api props;
@track state = { isLoading: false };
connectedCallback() {
this.state.isLoading = true;
this.props = this.props == undefined || this.props == null ? {} : JSON.parse(JSON.stringify(this.props));
}
renderedCallback() { }
onSubmit(event) {
//Commented Code used for future use
// if (this.checkValidation()) {
// this.btnToggel();
// this.state.isLoading = true;
// const fields = event.detail.fields;
// this.template.querySelector(‘lightning-record-edit-form’).submit(fields);
// }
this.btnToggel();
const fields = event.detail.fields;
this.template.querySelector(‘lightning-record-edit-form’).submit(fields)
}
onSuccess(event) {
this.state.isLoading = false;
this.props.recordid = event.detail.id;
this.showToastMessage(‘Success!’, ‘success’, this.props.sucessmessage);
this.btnToggel();
this.lightningNavigate({
type: ‘standard__recordPage’,
attributes: {
recordId: event.detail.id,
objectApiName: this.props.objectapiname,
actionName: ‘view’
}
});
}
onLoad(event) {
this.state.isLoading = false;
console.log(‘JSON Load Detail::’ + JSON.stringify(event));
}
onError(event) {
this.state.isLoading = false;
this.btnToggel();
// this.insertLog({ Class__c: ‘LwcRecordEditForm’, Method__c: ‘onError’, User__c: this.getuserInfo(), User_ID_Text__c: this.getuserInfo(), Type__c: ‘UI’, Message_Text__c: JSON.stringify(event) }); //Reserved for future use
this.showToastMessage(‘ERROR’, ‘error’, `DETAIL : ` + ‘\n’ + `\n ${event.detail.detail}`);
// Click on this link to show more way of customizing Error :https://developer.salesforce.com/docs/component-library/bundle/lightning-record-edit-form/documentation
}
get fieldWidth() {
return (FORM_FACTOR == ‘Large’) ? this.props.largeff : this.props.smallff;
}
btnToggel = () => {
this.template.querySelectorAll(‘.saveBtn’).forEach(el => {
el.disabled = !el.disabled;
})
}
//Commented Code used for future use
// checkValidation = () => {
// let elements = this.template.querySelectorAll(‘lightning-input-field’);
// alert(elements.length);
// for (let el = 0; el < elements.length; el++) {
// alert(JSON.stringify(elements[el]));
// if (elements[el].required && this.isEmpty(elements[el].value)) {
// this.showToastMessage(‘ERROR!’, ‘error’, `Missing or invalid field value [${elements[el].label}]`);
// return false;
// }
// }
// return false;
// }
}
lwcRecordEditForm
.main-parent {
position: relative;
margin: auto auto;
background-color: white;
border-radius: 0.25rem;
width: 100%;
max-height: 99%;
height: 99%;
padding-bottom: 60px;
}
/* Style the header with a grey background and some padding */
.header {
overflow: hidden;
background-color: #f3f2f2;
padding: 10px 10px;
position: sticky;
top: 0;
z-index: 10;
margin-bottom: 20px;
border-bottom: 2px solid #0070D2;
}
/* Style the header links */
.header a {
float: left;
color: black;
text-align: center;
padding: 12px;
text-decoration: none;
font-size: 16px;
line-height: 20px;
border-radius: 4px;
}
/* Style the logo link (notice that we set the same value of line-height and font-size to prevent the header to increase when the font gets bigger */
.header a.logo {
font-size: 20px;
font-weight: bold;
}
/* Change the background color on mouse-over */
.header a:hover {
background-color: #ddd;
color: black;
}
/* Style the active/current link*/
.header a.active {
background-color: dodgerblue;
color: white;
}
/* Float the link section to the right */
.header-right {
float: right;
}
/* Add media queries for responsiveness — when the screen is 500px wide or less, stack the links on top of each other */
@media screen and (max-width: 500px) {
.header a {
float: none;
display: block;
text-align: left;
}
.header-right {
float: none;
}
}
Request Parameter Types
props = {
objectapiname: ‘Account’, // Associated Object
layout: ‘auto’, // LayoutType
mode: ‘’, // Put some value if you want to work this in edit mode along with record id
recordid: ‘’, //recordid require for edit mode
recordtypeid: ‘’, // record type id
header: ‘CREATE ACCOUNT’, //header
headericon: ‘standard:account’,
headericonsize: ‘medium’,
btnlabel: ‘SAVE’,
variant: ‘standard’,
sucessmessage: ‘Record Updated Successfully !!’, //Success Message
errormessage: ‘’,
outercss: ‘’,
innercss: ‘’,
largeff: ‘slds-col slds-size_6-of-12 slds-p-horizontal_x-small’,
smallff: ‘slds-col slds-size_12-of-12 slds-p-horizontal_x-small’,
showcancel: false,
fieldSet:
[
{ apiname: ‘Name’, disabled: false, readonly: false, value: ‘’, required: false }, // required parameter is for future use
{ apiname: ‘Website’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘Active__c’, disabled: true, readonly: false, value: ‘’, required: false },
{ apiname: ‘AccountNumber’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘AccountSource’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘AnnualRevenue’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘BillingAddress’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘Description’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘NumberOfEmployees’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘Industry’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘Phone’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘SLA__c’, disabled: false, readonly: false, value: ‘’, required: false },
{ apiname: ‘User__c’, disabled: false, readonly: false, value: ‘’, required: false }
]
};
}
Complete code base can be found here in GitHub ..Please watch out for future enhancement . Also this code is not prod ready you need to customize based on use case . However please raise issue or suggest idea on GitHub .