Change Data Capture – Automate With LWC

Change Data Capture (CDC) Receive near-real-time changes of Salesforce records, and synchronize corresponding records in an external data store. Change Data Capture publishes change events, which represent changes to Salesforce records. Changes include creation of a new record, updates to an existing record, deletion of a record, and undeletion of a record. We can subscribe this in LWC using Emp Api.

Automate With Change Data Capture using Emp Api

Business asked to create a task whenever user manually change the status to Closed Won. Architect does not wants you to write apex trigger or create record triggered flows. This can be achieved by using Change Data Capture events and generic LWC placed on opportunity lightning record page.

How to enable CDC?

  • Go to setup
  • Search Change Data Capture
  • Add Entities
Change Data Capture (CDC) Receive near-real-time changes of Salesforce records, and synchronize corresponding records in an external data store. Change Data Capture publishes change events, which represent changes to Salesforce records. Changes include creation of a new record, updates to an existing record, deletion of a record, and undeletion of a record. Subscribe using emp api

Sample Response of CDC

This demonstrate the sample JSON response from Change Data Capture event paylaod.

{
  "data": {
    "schema": "F6bowHIr-cOJQX8LrZSSOQ",
    "payload": {
      "LastModifiedDate": "2023-01-18T09:19:02Z",
      "ForecastCategory": "Closed",
      "IsClosed": true,
      "ExpectedRevenue": 15000,
      "IsWon": true,
      "StageName": "Closed Won",
      "Probability": 100,
      "LastStageChangeDate": "2023-01-18T09:19:02Z",
      "ChangeEventHeader": {
        "commitNumber": 10932624199415,
        "commitUser": "005B0000008JWlBIAW",
        "sequenceNumber": 1,
        "entityName": "Opportunity",
        "changeType": "UPDATE",
        "changedFields": [
          "StageName",
          "Probability",
          "ExpectedRevenue",
          "IsClosed",
          "IsWon",
          "ForecastCategory",
          "ForecastCategoryName",
          "LastModifiedDate",
          "LastStageChangeDate"
        ],
        "changeOrigin": "com/salesforce/api/soap/57.0;client=SfdcInternalAPI/",
        "transactionKey": "00184570-30a2-a0f5-a9f3-d3c89a97026e",
        "commitTimestamp": 1674033542000,
        "recordIds": [
          "006B0000008v9DaIAI"
        ]
      },
      "ForecastCategoryName": "Closed"
    },
    "event": {
      "replayId": 65738599
    }
  },
  "channel": "/data/OpportunityChangeEvent"
}

Subscribe to CDC using Emp API in LWC

Let’s create a LWC with name changeDataCaptureSubscriber. This is very simple component that can be placed on any record page. We will be using it on Opportunity. As we are going to create task, We will use an apex controller named changeDataCaptureController.

changeDataCaptureController.cls

AssignTask is a simple apex method to insert a task and assign it to opportunity owner.

public with sharing class changeDataCaptureController {
    @AuraEnabled
    public static void AssignTask(String recordid){
        try {
            Opportunity opp = [select ownerId from Opportunity where id=:recordid];
            Task tsk = new Task();
            tsk.ownerId = opp.ownerId;
            tsk.WhatId = recordid;
            tsk.Subject = 'Complete Deal Closing Formalities';
            tsk.Status = 'Not Started';
            tsk.Priority = 'High';
            insert tsk;
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }
}

changeDataCaptureSubscriber.html

This component does not have any UI.

<template>
</template>

changeDataCaptureSubscriber.js

The lightning/empApi module provides access to methods for subscribing to a streaming channel and listening to event messages. All streaming channels are supported, including channels for platform events, PushTopic events, generic events, and Change Data Capture events. This component requires API version 44.0 or later.

import { LightningElement, api } from 'lwc';
import { subscribe, unsubscribe, onError } from 'lightning/empApi';
import AssignTask from '@salesforce/apex/changeDataCaptureController.AssignTask';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class ChangeDataCaptureSubscriber extends LightningElement {
    channelName = '/data/OpportunityChangeEvent';
    subscription = {};
    @api recordId;

    subscribed;

    // Tracks changes to channelName text field
    handleChannelName(event) {
        this.channelName = event.target.value;
    }

    renderedCallback() {
        if (!this.subscribed) {
            this.handleSubscribe();
            this.subscribed = true;
        }
    }

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

    }

    // Handles subscribe button click
    handleSubscribe() {
        // Callback invoked whenever a new event message is received
        const messageCallback = (response) => {
            console.log('New message received: ', JSON.stringify(response));
            // Response contains the payload of the new message received
            this.handleMessage(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
            console.log('Subscription request sent to: ', JSON.stringify(response.channel));
            this.subscription = response;
        });
    }

    // Handles unsubscribe button click
    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
        });
    }

    handleMessage(response) {
        if (response) {
            if (response.hasOwnProperty('data')) {
                let responsePayload = response.data.payload;
                if (responsePayload.hasOwnProperty('StageName') && responsePayload.hasOwnProperty('ChangeEventHeader')) {
                    if (responsePayload.ChangeEventHeader.hasOwnProperty('recordIds') && responsePayload.StageName == 'Closed Won') {
                        let currentRecordId = responsePayload.ChangeEventHeader.recordIds.find(element => element == this.recordId);
                        console.log('currentRecordId', currentRecordId);
                        if (currentRecordId) {
                            AssignTask({
                                recordid: this.recordId
                            }).then(result => {
                                const event = new ShowToastEvent({
                                    title: 'Task Assigned',
                                    message: 'A task has been assigned to you, please complete them.',
                                    variant: 'success'
                                });
                                this.dispatchEvent(event);
                            }).catch(error => {
                                console.log(error);
                            })
                        }
                    }

                }
            }
        }
    }
}

changeDataCaptureSubscriber.js-meta.xml

We are enabling the component to be used only with record page.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>56.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

Demo – CDC In LWC

Place your component on opportunity record page and change the stage to closed won. A task will be automatically created without having any apex trigger or record trigger flows.

Do you need help?

Are you stuck while working on this requirement? Do you want to get review of your solution? Now, you can book dedicated 1:1 with me on Lightning Web Component completely free.

GET IN TOUCH

Schedule a 1:1 Meeting with me

Also check out https://salesforcediaries.com/category/lightning-web-compont

Leave a Reply