Generic Record Edit Form — LWC

Rajesh Kumar
5 min readJan 6, 2021

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>

&nbsp; {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 .

--

--

Rajesh Kumar

Senior UI Developer - Salesforce & Other UI Tech