Change Data Capture (CDC) use with Lightning Web Component

LWC

With Change Data Capture, you can receive changes of Salesforce records in real time and synchronize corresponding records in an external data store. Change Data Capture publishes events for changes in Salesforce records corresponding to create, update, delete, and undelete operations.

When to Use Change Data Capture:-

  • Receive notifications of Salesforce record changes, including create, update, delete, and undelete operations.
  • Capture changes of most fields for all records.
  • Get information about the change in the event header, such as the origin of the change, so you can ignore changes that your client generates.
  • Perform data updates using transaction boundaries when more than one operation is part of the same transaction.

Use Case:-

  1. Suppose you want to see confirmation message on Account Record page when phone number is update by back end or external API without refresh entire record page.
  2. Suppose one opportunity is assigned to opportunity team members and you are also working on this on same time with another team members. if opportunity stage changed by Team member then this update stage will reflect on your side also without refresh record page.

For these use cases we need to use Change Data Capture.

All custom objects and few Standard Objects like  Account, Contact, Lead, User, Order, OrderItem, Product2, and others supports CDC.

Step 1:- We need to enabled Change Data Capture as below screen:

Step 2:- We need to create LWC component as below

changeDataCaptuerComponent.thml

<template>
</template>

changeDataCaptuerComponent.js

import { LightningElement,api } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { subscribe, unsubscribe, onError} from 'lightning/empApi';
import { getRecordNotifyChange } from 'lightning/uiRecordApi';

export default class ChangeDataCaptuerComponent extends LightningElement {
    @api recordId;
    channelName = '/data/AccountChangeEvent';

    subscription = {}; //subscription information
    responseMessage; //message to be shown at UI
    isDisplayMsg; //indicator for message to be displayed

    // Initializes the component
    connectedCallback() {       
        this.handleSubscribe();
        // Register error listener       
        this.registerErrorListener();   
    }

    // Handles subscribing
    handleSubscribe() {
        // Callback invoked whenever a new event message is received
        const messageCallback = (response) => {
            console.log('Update message received: ', JSON.stringify(response));
            // Response contains the payload of the new message received
            this.handleNotification(response);
        };

        // Invoke subscribe method of empApi. Pass reference to messageCallback
        subscribe(this.channelName, -1, messageCallback).then(response => {
            // Response contains the subscription information on subscribe call
            this.subscription = response;
            this.handleNotification(response); // this method use for refresh only particular filed value instead all entire page
           
        });
        this.handleUnsubscribe();// just unsucribe after complete action
    }

    // Handles unsubscribing
    handleUnsubscribe() {
        // Invoke unsubscribe method of empApi
        unsubscribe(this.subscription, response => {
            console.log('unsubscribe() response: ', JSON.stringify(response));
            // Response is true for successful unsubscribe
        });
    }


    registerErrorListener() {
        // Invoke onError empApi method
        onError(error => {
            console.log('Received error from server: ', JSON.stringify(error));
            // Error contains the server-side error
        });
    }

    //this method checks if current record got updated and shows message on UI
    handleNotification(response){
        if(response.hasOwnProperty('data')){
            let jsonObj = response.data;
            
            if(jsonObj.hasOwnProperty('payload')){
                let payload = response.data.payload;
                let recordIds = payload.ChangeEventHeader.recordIds;
                
              //Here you can add criteria for particular action like INSERT, UPDATE and DELETE with particuler Object
              //if(payload.ChangeEventHeader.entityName === 'Account')
              //if(payload.ChangeEventHeader.changeType === 'UPDATE')
              //if(payload.ChangeEventHeader.changedFields.includes('Phone') === 'UPDATE')


                //find the current recordId in the array and if found then display message
                const recId = recordIds.find(element=> element == this.recordId);
                if(recId !=undefined){
                    this.handleRefresh();
                }
            }
        }
    }

    //this method refreshes current record fields value instead of entire page
    handleRefresh(){
        getRecordNotifyChange([{recordId: this.recordId}]);
        const event = new ShowToastEvent({
            title: 'Success',
            message: 'Account phone update successfully!!',
            variant: 'success',
            mode: 'dismissable'
        });
        this.dispatchEvent(event);
    }

}

Step 3:- We need to put this component on Particular Lightning Record page where we want to get updated value. In this scenario we want to update Account phone number so we will put this component on Account Record Page as below:-

Step 4:- Just for testing open your developer console and update particular account phone by DML and after this operation check your account record page that’s already opened, now updated Phone Number will be reflect on record page.

Trailhead

After update operation you will get payload as below

Event payload structure:-

{
“data”:
{“schema”:”JPyUm_b7b4SSjXobT5DOPg”,
“payload”:
{“LastModifiedDate”:”2023-02-17T04:28:38Z”,”Phone”:”999999999″,
“ChangeEventHeader”:
{“commitNumber”:603217770054,”commitUser”:”0055h000007V4S3AAK”,”sequenceNumber”:1,”entityName”:”Account”,”changeType”:”UPDATE”,
changedFields“:[“Phone“,”LastModifiedDate”],”changeOrigin”:”com/salesforce/api/rest/57.0″,”transactionKey”:”0000b8b9-3a08-ffa6-efe2-efefea45484f”,”commitTimestamp”:1676608118000,”recordIds”:[“0015h000015Ed44AAC”]
}
}
,”event”:{“replayId”:25397141}
},
“channel”:”/data/AccountChangeEvent”
}

uniquesymbol

Leave a Reply