Friday, November 1, 2024

Profiles are retiring soon by Spring 2026 release! What Next?

Salesforce has officially announced that profiles will no longer serve as the primary method for managing permissions, with their retirement slated for Spring 2026.

While profiles will still exist, their functionality will be scaled back to basics, such as login hours and default settings. When setting up a user, profiles will still be required, but their role will be limited to managing things like:

  • Login hours and IP ranges
  • Record types and default apps
  • Page Layout Assignment will be still managed by profiles (Salesforce won't move this to permission sets as the future is App builder/Dynamic forms.

What's Changing?

  1. Key Permissions Shift to Permission Sets:
    Permissions like CRUD, field-level security, app access, and more will now be managed through permission sets.

  2. Enhanced Flexibility with Layered Permissions:
    You’ll be able to stack multiple permission sets and use permission set groups, providing greater flexibility for user access management.

  3. Simplified Administration:
    This transition reduces complexity, especially for large organizations with an overabundance of profiles.

Although this marks a major shift, it’s intended to streamline user management and simplify life for administrators in the long run.

Get Ahead of the Change:

Start planning your migration to permission sets today to ensure a smooth transition.

Saturday, October 26, 2024

What is Change Data Capture in Salesforce?

Change data capture is a streaming product also called CDC helps you to integrate your Salesforce data with external systems in real time for operation such as creation of a new record, updates to an existing record, deletion of a record, and undeleting of a record. This is very helpful in cases where we need to keep external system in sync with Salesforce in real time instead of doing periodic exports and Imports of data or repeated API calls.

 Availability for Standard and Custom objects for CDC and there syntax for usage with CDC :

 Change events are available for all custom objects defined in your Salesforce org and a subset of standard objects. A ChangeEvent object is available for each object that supports Change Data Capture. A change event isn’t a Salesforce object. It doesn’t support CRUD operations or queries. It’s included in the object reference so you can discover which Salesforce objects support change events. The name of a change event is based on the name of the corresponding object for which it captures the changes.

 Standard Object Change Event Name: <Standard_Object_Name>ChangeEvent

 As an example for Account we will use AccountChangeEvent.

 Custom Object Change Event Name: <Custom_Object_Name>__ChangeEvent

 As an example, for MyCustomObject__c we will use MyCustomObject__ChangeEvent.

 Security with Change Data Capture:

 Change Data Capture ignores sharing settings and sends change events for all records of a Salesforce object. Using Change Data Capture we can capture field changes for all records, CDC Deliver only the fields a user has access to based on field-level security. The fields that a change event doesn’t include are:

 The IsDeleted system field.

The SystemModStamp system field.

Any field whose value isn’t on the record and is derived from another record or from a formula, except roll-up summary fields, which are included.

Sample event message in JSON format for a new account record creation:

This example is an event message in JSON format for a new account record creation.

{

  "schema": "IeRuaY6cbI_HsV8Rv1Mc5g",

  "payload": {

    "ChangeEventHeader": {

      "entityName": "Account",

      "recordIds": [

        "<record_ID>"

      ],

      "changeType": "CREATE",

      "changeOrigin": "com/salesforce/api/soap/51.0;client=SfdcInternalAPI/",

      "transactionKey": "0002343d-9d90-e395-ed20-cf416ba652ad",

      "sequenceNumber": 1,

      "commitTimestamp": 1612912679000,

      "commitNumber": 10716283339728,

      "commitUser": "<User_ID>"

    },

    "Name": "Acme",

    "Description": "Everyone is talking about the cloud. But what does it mean?",

    "OwnerId": "<Owner_ID>",

    "CreatedDate": "2021-02-09T23:17:59Z",

    "CreatedById": "<User_ID>",

    "LastModifiedDate": "2021-02-09T23:17:59Z",

    "LastModifiedById": "<User_ID>"

  },

  "event": {

    "replayId": 6

  }

}

How to enable Change Data Capture?

To receive notifications on the default standard channel for record changes, select the custom objects and supported standard objects that you’re interested in on the Change Data Capture page.

From Setup, in the Quick Find box, enter Change Data Capture, and click Change Data Capture. The Available Entities list shows the objects available in your Salesforce org for Change Data Capture, You can select up to five entities, including standard and custom objects. To enable more entities, contact your Salesforce Account Representative to purchase an add-on license. The add-on license removes the limit on the number of entities you can select. Also, it increases the event delivery allocation for CometD and Pub/Sub API clients. With the add-on license, you can select up to 10 entities at a time in the Available Entities list. After selecting the first 10 entities, you can add more.

What is CDC in salesforce?

Note: You can also create a custom channel if you have multiple subscribers and each subscriber receives change events from a different set of entities. Also, use a custom channel with event enrichment to isolate sending enriched fields in change events on a specific channel. Custom channels group and isolate change events for each subscriber so subscribers receive only the types of events they need.

Subscribe to Change Events:

 You can subscribe to change events with CometD, Pub/Sub API, or Apex triggers.

 Let us try to understand with an example,

 Now, to view the CDC, open the workbench à Open queries tab à Streaming Push Topics.

 Click Generic Subscriptions à and type /Data/AccountChangeEvent and click Subscribe.

 The connection is established now as you can see in below image.

 

How to use Change Data Capture in Salesforce

As we have setup CDC for Account above. Let us try to update an account record and click Save.

Change Data Capture in Salesforce

Now, go back to workbench. You will be able to see the notification as shown below.

How to use Change Data Capture in Salesforce

Sunday, September 22, 2024

What are events in LWC? How Communications happens in LWC?

In Lightning Web Components (LWC), events are used for communication between components, particularly for passing information or triggering actions. 

In Lightning Web Components (LWC), there are three primary approaches for communication between components using events:

  1. Parent-to-Child Communication: This allows a parent component to pass data or trigger actions in a child component via public properties or methods.

  2. Child-to-Parent Communication (Custom Events): Child components can send data or trigger actions in their parent component by dispatching custom events.

  3. Publish-Subscribe Pattern (LMS): This pattern enables communication between two components that do not have a direct parent-child relationship, using the Lightning Message Service (LMS) to broadcast and subscribe to events across the application. 

Event Phase in LWC:

Lightning web components use only the bubbling phase. Dispatching events or adding listeners to the capture phase isn't supported. Simply think of the event’s path as starting with your component and then moving to its parent, and then grandparent, and so on.

Parent-to-Child Communication:

In Lightning Web Components, data can be passed from a parent to a child component using the following two methods:

1. Public Properties: These are reactive properties defined in the child component that the parent component can set directly.


2. Public Methods: These are methods in the child component that the parent component can invoke to pass data or trigger specific behavior.


Child-to-Parent Communication (Custom Events)

Child to Parent communication is achieved by triggering custom event from child LWC and handling it parent LWC as explained in blog: https://www.sfdc-lightning.com/2020/01/how-to-pass-data-from-child-component-to-parent-component-in-lightning-web-component.html

We will see the use of Publish-Subscribe Pattern (LMS) in our next blog.

Monday, September 16, 2024

What is Shadow DOM in LWC?

In Lightning Web Components (LWC), encapsulation refers to the isolation of a component’s internal structure, styles, and behavior from the rest of the application. This is primarily achieved using the Shadow DOM, which ensures that the component’s logic remains self-contained and unaffected by external factors, allowing it to function independently.The styles defined inside a component are scoped to that component and do not affect other components or the global application.The component’s internal DOM is hidden from the outside world, ensuring that its structure and behavior cannot be directly manipulated by external code.

In the below example, Shadow DOM in Lightning Web Components (LWC) is used to encapsulate the styles and DOM structure of the parent and child components, preventing style leakage between them:

The parent component (`ParentShadowDOM`) defines a `<p>` tag with blue text and large font, which applies only to the parent due to Shadow DOM encapsulation.

The child component (`childLWCComp`) has its own `<p>` tag styled with red text and small font.

Since both components use Shadow DOM, the styles of the parent component do not affect the child component, and vice versa, ensuring complete isolation of their DOM structure and styles. This maintains a clear separation between the two components, allowing each to have its own independent styling and behavior.

parentShadowDOM.html

<template>

    <div><p>I am parent comp</p></div>

    <div>

  <c-child-lwc-comp></c-child-lwc-comp>

    </div>

</template>

parentShadowDOM.js

import { LightningElement } from 'lwc';

export default class ParentShadowDOM extends LightningElement {}

parentShadowDOM.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">

    <apiVersion>61.0</apiVersion>

    <isExposed>false</isExposed>

</LightningComponentBundle>

parentShadowDOM.css

p{

    color: blue;

    font-size: large;

}

childLWCComp.html

<template>

    <div><p>I am child comp</p></div>

</template>

childLWCComp.js

import { LightningElement } from 'lwc';


export default class ChildLwcComp extends LightningElement {}

childLWCComp.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">

    <apiVersion>61.0</apiVersion>

    <isExposed>false</isExposed>

</LightningComponentBundle>

childLWCComp.css

p{

    color: red;

    font-size: small;

}

Let us now preview this component for testing by adding it in Aura App as shown below.

<aura:application>

<c:parentShadowDOM></c:parentShadowDOM>

</aura:application>


What is Shadow DOM in LWC?

Saturday, July 27, 2024

Update Number Of Child Contacts on Account for Contact changes

 he UpdateContactCountOnAccount trigger ensures that the custom field Number_Of_Child_Contacts__c on the parent Account is updated with the correct count of associated Contacts. It runs after insert, after update, after delete, and after undelete on the Contact object. The trigger collects Account IDs for Contacts being processed, queries all related Contacts, manually counts them, and updates the custom field on the corresponding Accounts. 


trigger UpdateContactCountOnAccount on Contact (after insert, after update, after delete, after undelete) {

    Set<Id> accountIdsToUpdate = new Set<Id>();

    if (Trigger.isInsert || Trigger.isUndelete) {

        for (Contact c : Trigger.new) {

            accountIdsToUpdate.add(c.AccountId);

        }

    } else if (Trigger.isUpdate) {

        for (Contact c : Trigger.new) {

            accountIdsToUpdate.add(c.AccountId);

        }

        for (Contact c : Trigger.old) {

            accountIdsToUpdate.add(c.AccountId);

        }

    } else if (Trigger.isDelete) {

        for (Contact c : Trigger.old) {

            accountIdsToUpdate.add(c.AccountId);

        }

    }

    // Map to hold accountId and corresponding contact count

    Map<Id, Integer> accountContactCountMap = new Map<Id, Integer>();

    // Initialize the map with account IDs

    for (Id accountId : accountIdsToUpdate) {

        accountContactCountMap.put(accountId, 0);

    }

    // Query all contacts for the accounts to be updated

    List<Contact> contacts = [

        SELECT AccountId 

        FROM Contact 

        WHERE AccountId IN :accountIdsToUpdate

    ];

    // Count the number of contacts for each account

    for (Contact contact : contacts) {

        if (accountContactCountMap.containsKey(contact.AccountId)) {

            accountContactCountMap.put(contact.AccountId, accountContactCountMap.get(contact.AccountId) + 1);

        } else {

            accountContactCountMap.put(contact.AccountId, 1);

        }

    }

    // Prepare the list of accounts to be updated

    List<Account> accountsToUpdate = new List<Account>();

    for (Id accountId : accountContactCountMap.keySet()) {

        accountsToUpdate.add(new Account(Id = accountId, Number_Of_Child_Contacts__c = accountContactCountMap.get(accountId)));

    }

    // Update the accounts

    if (!accountsToUpdate.isEmpty()) {

        update accountsToUpdate;

    }

}