What we are building today?
A Lighting web component which will allow user to update parent details from child record.
What does that mean? Example: On Opportunity we have custom parents object Parent Object 1, Parent Object 2 and we want to update their details from child(Opportunity) it self.
NOTE: Using standard Related Record component we can update parent record details from child.
Watch a quick demo
What you will learn?
- Get parent objects of any custom or standard object using apex (get all parents of Accounts)
- Get all updatable fields of any salesforce object
- Dynamically get label of any custom or standard object in Apex
- Using Schema.getGlobalDescribe() method
- How to use lightning-record-edit-form and display fields dynamically
- Dynamically pass current object name and record to lightning-record-edit-form
- Passing options to lightning-combobox dynamically
- How to use uiRecordApi of LDS
- Get record details using getRecord of LDS uiRecordApi
- Dynamically use ShowToastEvent to display Success & Error popups
We have covered all the about topics in this post, now lets dig to each of these. Find the combined version at last, copy and paste it to see in demo action.
Get all parent of any salesforce object dynamically:
@AuraEnabled
public static Map < String, String > getParentObjects(String childObject) {
Map < String, String > mapParentObjects = new Map < String, String > ();
String SobjectApiName = childObject;
Map < String, Schema.SObjectType > schemaMap = Schema.getGlobalDescribe();
for (Schema.SobjectField fldMap: schemaMap.get(SobjectApiName).getDescribe().fields.getMap().Values()) {
String customField = fldMap.getDescribe().getName();
if (customField.endsWith('__c') && fldMap.getDescribe().getType() == Schema.DisplayType.REFERENCE) {
List < SObjectType > refObjs = fldMap.getDescribe().getReferenceTo();
String objectName = String.valueOf(refObjs[0]);
mapParentObjects.put(getObjectLabel(objectName), objectName);
}
}
return mapParentObjects;
}
Dynamically get all updatable fields of any object in Apex:
@AuraEnabled
public static Map < String, String > getUpdatableFields(String strObjectName) {
Map < String, Schema.SObjectType > detail = Schema.getGlobalDescribe();
Map < String, String > mapOfPicklistTypeFields = new Map < String, String > ();
for (Schema.SObjectField fields: detail.get(strObjectName).getDescribe().fields.getMap().Values()) {
If(fields.getDescribe().isAccessible() && fields.getDescribe().isCreateable() && fields.getDescribe().isUpdateable()) {
mapOfPicklistTypeFields.put(fields.getDescribe().getLabel(), fields.getDescribe().getName());
}
}
return mapOfPicklistTypeFields;
}
Method of get object label:
public static String getObjectLabel(String objectName) {
Map < String, SObjectType > sObjects = Schema.getGlobalDescribe();
return sObjects.get(objectName).getDescribe().getLabel();
}
Fetch current record object name and record Id in LWC:
Use @api recordId and @api objectApiName to get current record Id and object name in lighting component.
IMP NOTE: Sometimes you may get undefined value in both of the about property, just remove the component from page insert it again to fix it.
@api recordId;
@api objectApiName;
Complete code to build parent record updater
Apex Class:
public with sharing class UpdateParentFromChild {
@AuraEnabled
public static Map < String, String > getParentObjects(String childObject) {
Map < String, String > mapParentObjects = new Map < String, String > ();
String SobjectApiName = childObject;
Map < String, Schema.SObjectType > schemaMap = Schema.getGlobalDescribe();
for (Schema.SobjectField fldMap: schemaMap.get(SobjectApiName).getDescribe().fields.getMap().Values()) {
String customField = fldMap.getDescribe().getName();
if (customField.endsWith('__c') && fldMap.getDescribe().getType() == Schema.DisplayType.REFERENCE) {
List < SObjectType > refObjs = fldMap.getDescribe().getReferenceTo();
String objectName = String.valueOf(refObjs[0]);
mapParentObjects.put(getObjectLabel(objectName), objectName);
}
}
return mapParentObjects;
}
public static String getObjectLabel(String objectName) {
Map < String, SObjectType > sObjects = Schema.getGlobalDescribe();
return sObjects.get(objectName).getDescribe().getLabel();
}
@AuraEnabled
public static Map < String, String > getUpdatableFields(String strObjectName) {
Map < String, Schema.SObjectType > detail = Schema.getGlobalDescribe();
Map < String, String > mapOfPicklistTypeFields = new Map < String, String > ();
for (Schema.SObjectField fields: detail.get(strObjectName).getDescribe().fields.getMap().Values()) {
If(fields.getDescribe().isAccessible() && fields.getDescribe().isCreateable() && fields.getDescribe().isUpdateable()) {
mapOfPicklistTypeFields.put(fields.getDescribe().getLabel(), fields.getDescribe().getName());
}
}
return mapOfPicklistTypeFields;
}
}
LWC HTML:
<template>
<div class="slds-card">
<lightning-combobox class="slds-grid slds-col slds-size_2-of-3"
name="parentObjects"
label="Select Parent Object"
value={value}
placeholder="Select Object"
options={options}
onchange={handleParentObjectChange} >
</lightning-combobox>
<div lwc:if={showEditForm} >
<lightning-record-edit-form object-api-name={parentObject} record-id={parentRecordId} onsuccess={handleSuccess} onerror={handleError}>
<template for:each={fieldsToUpdate} for:item="currentItem" for:index="index">
<!-- <lightning-layout-item key={currentItem.value} size="6" class="slds-grid">
<lightning-input-field field-name={currentItem.value}> </lightning-input-field>
</lightning-layout-item> -->
<lightning-input-field key={currentItem.value} field-name={currentItem.value}> </lightning-input-field>
</template>
<div class="slds-var-m-top_medium">
<lightning-button variant="brand" type="submit" label="Update"></lightning-button>
</div>
</lightning-record-edit-form>
</div>
</div>
</template>
LWC JS:
import { LightningElement, track, api, wire } from 'lwc';
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import getParentObjects from '@salesforce/apex/UpdateParentFromChild.getParentObjects';
import getUpdatableFields from '@salesforce/apex/UpdateParentFromChild.getUpdatableFields';
import { getRecord } from "lightning/uiRecordApi";
export default class UpdateParentFromChild extends LightningElement {
@track options = [];
@track fieldsToUpdate = [];
@track showEditForm = false;
@api recordId;
@api objectApiName;
@track parentRecordId;
@track childRecordData;
connectedCallback() {
this.getParentObjects();
this.childRecordId = this.recordId;
console.log('objectApiName 1' , this.objectApiName);
}
@wire(getRecord, { recordId: "$childRecordId", layoutTypes: ["Full"], modes: ["View"] })
childData({ error, data }) {
if (data) {
this.childRecordData = data;
} else (
console.log('error in getting company url',error)
)
}
getParentObjects() {
getParentObjects({ childObject: this.objectApiName })
.then(result => {
this.options = [];
for (let key in result ) {
this.options.push({ label: key, value: result[key] });
}
})
.catch(error => {
this.showToast('Error', 'Error getting parent objects', 'error')
});
}
handleParentObjectChange(event) {
this.showEditForm = false;
this.parentRecordId = '';
this.parentObject = event.detail.value;
this.parentRecordId = this.childRecordData.fields[this.parentObject].value
this.getUpdatableFields(this.parentObject);
}
getUpdatableFields() {
getUpdatableFields({ strObjectName: this.parentObject})
.then(result => {
this.fieldsToUpdate = [];
for (let key in result ) {
this.fieldsToUpdate.push({ label: key, value: result[key] });
}
if(this.parentRecordId && this.parentRecordId != '') {
this.showEditForm = true;
} else {
this.showToast('Warning', 'Parent not linked', 'warning')
}
})
.catch(error => {
this.showToast('Error', 'Error getting updatable fields', 'error')
});
}
handleSuccess() {
this.showToast('Success', 'Child record updated', 'success')
}
handleError() {
this.showToast('Error', 'Error in updating child record', 'error')
}
showToast(title, message, variant) {
const evt = new ShowToastEvent({
title: title,
message: message,
variant: variant,
});
this.dispatchEvent(evt);
}
}
LWC XML:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Update Parent Record</masterLabel>
<targets>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>