Use Case:
Since the inception of LWC, we have been using the lightning web components in many of the customizations. One of the areas is to embed our LWC in the Lightning Record Pages for any Standard and/or Custom objects. Right now, if we are using the Apex methods(Imperative approach) to update the record, we are not able to refresh or get the updated record detail page with the latest changes by default.
In AURA we have the force:refreshView event which we can fire explicitly and the Lightning Data Service with update the cache. In LWC, we don't have any such event which allows the Lightning Data Service refresh the cache. To achieve this with LWC, there are couple of approaches
- Fire refreshView event from LWC: Considered as a workaround as not an ideal approach.
- Use getRecordNotifyChange in LWC: This approach is more promising and assures of great performance and stability. It fetches record updates for the specified record IDs and refresh the Lightning Data Service cache, providing your wires with the latest record data. Call this function to notify Lightning Data Service that a record has changed outside its mechanisms, such as via imperative Apex or Visualforce, or by calling User Interface API via a third-party framework.
To ensure that getRecordNotifyChange() is called after the record is updated via Apex(Imperative call), use the async/await annotated function or a Promises in JavaScript.
Benefits of using getRecordNotifyChange:
- It is an advanced version of force:refreshView
- Unlike force:refreshView, it refreshes those record details only whose Ids are specified and given to getRecordNotifyChange
- Better performance
- It can update more then one records. All you need is to provide the array of record ids to this method. See example here.
Implementation:
-
Create APEX class Accounts
public class Accounts { @AuraEnabled public static Account updateAccountRecord(String recordId, String accountName) { Account acc = new Account(Id = recordId, Name = accountName); update acc; return acc; } }
- Create LWC updateRecordDetail
-
updateRecordDetail.html
<template> <div class="slds_card"> <!-- Example of auto UI refresh with LDS --> <div class="recordEditForm"> <lightning-record-edit-form object-api-name={objectApiName} record-id={recordId}> <lightning-input-field field-name={name}></lightning-input-field> <div class="slds-var-m-top_medium"> <lightning-button variant="brand" onclick={handleSubmit} label="Save via LDS"> </lightning-button> </div> </lightning-record-edit-form> </div> <!-- Example of auto UI refresh with Apex call --> <div class="regularInput" if:true={account}> <lightning-input name="Account Name" label="Account Name" value={accountName} required="true"> </lightning-input> <div class="slds-var-m-top_medium slds-list_horizontal"> <div class="slds-var-p-right_small"> <lightning-button variant="brand" onclick={handleSave} label="Save via ui Record API utility"> </lightning-button> </div> <div> <lightning-button variant="brand" onclick={handleSaveApex} label="Save via Apex"> </lightning-button> </div> </div> </div> </div> <div if:true={showSpinner}> <lightning-spinner alternative-text="Loading" size="medium"></lightning-spinner> </div> </template>
-
updateRecordDetail.js
import { LightningElement, api, wire } from 'lwc'; import NAME_FIELD from '@salesforce/schema/Account.Name'; import ID_FIELD from '@salesforce/schema/Account.Id'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import { updateRecord, getFieldValue, getRecord, getRecordNotifyChange } from 'lightning/uiRecordApi'; import updateRecordApex from '@salesforce/apex/Accounts.updateAccountRecord'; const accountFields = [NAME_FIELD]; export default class UpdateRecordDetail extends LightningElement { @api recordId; @api objectApiName; showSpinner = false; name = NAME_FIELD; account; //get the account name field property get accountName() { return getFieldValue(this.account, NAME_FIELD); } @wire(getRecord, { recordId: '$recordId', fields: accountFields }) wiredAccount(value) { if (value.data) this.account = value.data; else this.account = undefined; }; //update the record with lightning record edit form LDS service handleSubmit(event){ event.preventDefault(); // stop the form from submitting const fields = event.detail.fields; console.log('in updateRecord LDS'); this.showSpinner = true; this.template.querySelector('lightning-record-edit-form').submit(fields); this.dispatchEvent( new ShowToastEvent({ title: 'Success', message: 'Account Name updated using LDS', variant: 'success' }) ); this.showSpinner = false; } //update the record with uiRecordAPI handleSave(event) { event.preventDefault(); let accountName = this.template.querySelector("lightning-input").value; const fields = {}; fields[ID_FIELD.fieldApiName] = this.recordId; fields[NAME_FIELD.fieldApiName] = accountName; const recordInput = { fields }; this.updateRecord(recordInput); } //refreshes the cache defaultly updateRecord(recordInput) { console.log('in updateRecord uiRecordAPI'); this.showSpinner = true; updateRecord(recordInput) .then(() => { this.dispatchEvent( new ShowToastEvent({ title: 'Success', message: 'Account Name updated using uiRecordAPI', variant: 'success' }) ); this.showSpinner = false; }) .catch(error => { console.log('error in updateRecord: ' + JSON.stringify(error)); this.showSpinner = false; }); } //update the record with apex handleSaveApex(event) { event.preventDefault(); let accountName = this.template.querySelector("lightning-input").value; this.updateRecordApex(accountName); } //refreshes the cache explicitly updateRecordApex(accountName) { console.log('in updateRecord Apex'); this.showSpinner = true; updateRecordApex({ 'recordId': this.recordId, accountName }) .then(() => { this.dispatchEvent( new ShowToastEvent({ title: 'Success', message: 'Account Name updated using Apex', variant: 'success' }) ); //either use the eval row(#100) or getRecordNotifyChange row(#101) to refresh cache explicitly //eval("$A.get('e.force:refreshView').fire();"); getRecordNotifyChange([{ recordId: this.recordId }]); this.showSpinner = false; }) .catch(error => { this.showSpinner = false; console.log('error in updateRecordApex: ' + JSON.stringify(error)); }); } }
-
updateRecordDetail.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>54.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__RecordPage</target> </targets> </LightningComponentBundle>
- Update Account Flexi page: Edit the Account flexi page(Lightning Record Page) and add the new LWC updateRecordDetail and save.
Demo:
References:
If you like this blog content and find inciteful, please comment and let me know.
Great article on explicitly refreshing the standard record detail page using LWC! This is incredibly helpful for improving user experience and ensuring real-time updates without manual intervention. As a Salesforce development company in USA, we often leverage techniques like this to build dynamic and efficient solutions for our clients. Thanks for sharing this practical guide!
ReplyDelete