Sunday, March 26, 2023

Custom Events in Lightning Web Components : Pass data from child component to parent component

In order to communicate from child component to parent component in LWC, we use custom events. Custom events helps in passing data from child components to parent component in containment hierarchy.

If you want to refer on how same thing can be achieved in Aura Components then refer below article:

Component Events: Way to Communicate Between Components in Containment Hierarchy


Lightning component can create and dispatch events in a component’s JavaScript class. To create an event, use the CustomEvent() constructor. To dispatch an event, call the EventTarget.dispatchEvent() method.

The CustomEvent() constructor needs one required parameter, which is a string indicating what event has been performed. You can define ant string as event name. While defining event name, follw below recommendation based on DOM event standard.

  • No uppercase letters
  • No spaces
  • Use underscores to separate words

Steps involved in implementing custom events

1. Create custom event in child component and dispatch that event.

    const newEvent = new CustomEvent("search");
    this.dispatchEvent(newEvent);

2. Handle the event in parent component.

When you declare the child component in parent component, then use "on" event handler to execute logic whenever the event is fired. Suppose you event name which is dispateched from child component is "search", event handler name will be "onsearch".

<c-sk-child-cmp onsearch={capturedEvent}></c-sk-child-cmp>
capturedEvent(event) {
    console.log("**recieved event-->" + event);
}

Custom events to inform what action is performed in child component

If you want to inform parent component about what has been clicked or operation performed in child component, then you can simply define custom event as mentioned below:

<template>
    <lightning-button label="Edit" onclick={editAction}></lightning-button>
    <lightning-button label="New" onclick={deleteAction}></lightning-button>
</template>

    editAction() {
const newEvent = new CustomEvent("edit");
        this.dispatchEvent(newEvent);
    }

    deleteAction() {
const newEvent = new CustomEvent("delete");
        this.dispatchEvent(newEvent);
    }


Custom events to pass data to parent component

If you want to pass data to parent component, then set a detail property in the CustomEvent constructor. 

You can pass any record id  or any data from child component in detail property.

@track selectedRecordId;

handleResponse(event) {
const answerEvent = new CustomEvent("search", { detail: this.selectedRecordId});
this.dispatchEvent(answerEvent);
}

Parent component can access detail property in order to read data passed from child component

 capturedEvent(event) {
    console.log("**recieved event detail-->" + event.detail);
 }


Note: There is no restriction on data type of detail property but is is recommended to pass only primitive data. JavaScript passes all data types by reference except for primitives. If a component includes an object in its detail property, any listener can mutate that object without the component’s knowledge. This is a bad thing! It’s a best practice either to send only primitives, or to copy data to a new object before adding it to the detail property. Copying the data to a new object ensures that you’re sending only the data you want, and that the receiver can’t mutate your data.

Lets try to understand custom events through simple example:

We will create a child component "skChildCmp" which will contain few buttons. Once user will click on one of the button, child component will pass resource URL based on button click to parent component and parent component will display that URL.

Below is snapshot for parent component:


Now when user clicks on SFDCSTUFF BLOGS button, URL for that button will be appearing on parent component.


If user clicks on TRAILHEAD button, then parent will display URL for that.


Below is complete code snippet:



Hope this will help!!

Thursday, October 13, 2022

lightning-tree-grid - Account Hierarchy Using lightning-tree-grid in LWC

 In this blog, I am going share a approach through which you can display account hierarchy using lightning tree grid. You can place this lightning component on account record page and it will detect the current account record Id and will display the complete hierarchy.

I am utilising formula field called "Ultimate Account id" to avoid multiple SOQL in apex to get list of all account in the hierarchy. This component can display all account which are up to 10 level deep in hierarchy.

Please refer below URL to get more idea about Ultimate Account Id formula field.

How to get list of all accounts present in account hierarchy in Salesforce

In this LWC component, I am just passing the account Id to apex method and apex method returns all the account list which are present in hierarchy. In order to display account in tree grid, I am creating data in js which will be accepted by tree grid. So in this approach, manipulation on apex side is very simple.


Note: Create Ultimate Account Id formula field on account first in order to implement below code.

Complete Code:

Hope this will help!!!




Wednesday, October 12, 2022

How to get list of all accounts present in account hierarchy in Salesforce

 As a developer, we always get requirement to display records in their hierarchy (Account Hierarchy, Case Hierarchy etc). Using SOQL queries, its really tough to get all accounts in hierarchy as we have to fire multiple SOQL queries to get ultimate parent record id if we are on a record which is 3 or 4 level down in hierarchy. 

Instead of achieving everything using SOQL, we can create formula field "Ultimate Account Id" in account object which will store ultimate account record id on all account records present in account hierarchy. As formula field allows you to refer upto 10 parent, we can easily get list of all account in account hierarchy upto 10 levels.


Below is formula for Ultimate Account Id.


Now if you know account record id, just get Ultimate Account Id field value and then query all accounts which have this ultimate account Id.

Below is static method which can be used to get list of all account present in account hierarchy.

public static list<Account> findAllHierarchyAccounts(string recordId){
list<Account> allAccountList=new List<Account>();
string ultimateAccountId;
for(Account acc:[select Ultimate_Account_Id__c from Account where Id=:recordId]){
ultimateAccountId=acc.Ultimate_Account_Id__c;
}
if(string.isNotBlank(ultimateAccountId)){
for(Account acc:[select id,Name,ParentId
from Account where Ultimate_Account_Id__c=:ultimateAccountId]){
allAccountList.add(acc);
}
}
system.debug('***allAccountList size:'+allAccountList);
return allAccountList;
}

Hope this will help!!


Wednesday, April 20, 2022

Considerations for using Platform Events

Platform really helps in setting up custom notifications within salesforce or for external system. While utilising the platform events in salesforce, you need to consider below things:

  • Record Owner considerations

Whenever you create record from after insert using triggers, then ownerid of those records will be Automated Process by default. If you have set current user as record owner, then specify ownerid of created records as createdbyId of event.

Account acc= new Account(name='test account through Demo platform event',OwnerId = event.createdById);

  • Platform Event Trigger do not provide Email Support
As automated process user does not have email address, sending an email message from a platform event trigger using the Messaging.SingleEmailMessage class is not supported. As a workaround, send emails via email alert where the From Email Address is NOT "Current User's Email Address" but rather some other organization-wide email or default workflow user. 

In Apex, use the SingleEmailMessage.setOrgWideEmailAddressId method to set the org-wide email. 

Hope this will help!!

Thursday, May 27, 2021

Useful system application events for lightning developement

Below is list of application events which is very useful and can be used frequently in lightning development.

Note: These events are supported in Lightning Experience, the Salesforce mobile app, and Aura-based Experience Builder sites.


  • force:closeQuickAction

To close a quick action panel, you can use force:closeQuickAction event
var navEvent = $A.get("e.force:closeQuickAction");
if(navEvent){
navEvent.fire();
}

  • force:navigateToList
This event helps you to navigate to list view based on ListviewId specified.

var navEvent = $A.get("e.force:navigateToList");
if(navEvent){
navEvent.setParams({
"listViewId": listviews.Id,
"listViewName": null,
"scope": "Account"
});
navEvent.fire();
}
                               
How to get list view id using SOQL
SELECT Id FROM ListView WHERE SobjectType = 'Account' and Name='All Accounts' Limit 1

  • force:navigateToURL
This event helps you to navigate to URL specified in parameter.

var navEvent= $A.get("e.force:navigateToURL");
if(navEvent){
navEvent.setParams({
      "url": "/001/"
    });
navEvent.fire();
}

  • force:refreshView
To refresh or reload standard or custom component, use this event. This event ideally reload data without page refresh.

var navEvent= $A.get("e.force:refreshView");
if(navEvent){
navEvent.fire();
}

Note: This event impact performance and should be avoided. Also avoid repeated firing of this event from same component

  • force:showToast
This event can be used to display message below the header at the top of a view. You can specify the message and type (warning, success, info, other) and based on that color of message panel will changes. Default is other which shows panel similar to info.

showToastMessage:function(title,msg,duration,key,type,mode){
var toastEvent = $A.get("e.force:showToast");
if(toastEvent){
toastEvent.setParams({
"title": title,
"message": msg,
"duration":duration,
"type": type,
"mode": mode
});
toastEvent.fire();
}
}

Default value for mode is "dismissible" which display close icon. In duration you can specify the time in millisecond. Toast will remain in screen for this duration.


  • force:force:navigateToSObject
This event help you to navigate to record details page based on recordId specified:

var navEvent= $A.get("e.force:navigateToSObject");
if(navEvent){
navEvent.setParams({
"recordId": "003B0000000ybYX"
});
navEvent.fire();
}


Hope this help!!

Saturday, March 20, 2021

System.TypeException: Cannot have more than 10 chunks in a single operation

 While working on requirement where we have to perform DML on multiple object dynamically by using sobject, we got below error:


"System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking."


This kind of error appears if your list of sobject contains more than 10 types of object records or record of objects are not ordered based on object. For example if you are adding lead, account and contact record to sobject list by using below format:

Lead1,Account1,Contact1,Lead2,Account2,Contact2,Lead3,Account3,Contact3,Lead4,Account4,Contact4

This will be considered as 12 chunks on sobject and while performing DML, you will get this error.

If you want to avoid it, then rearrange the records in below format:

Lead1,Lead2,Lead3,Lead4,Account1,Account2,Account3,Account4,Contact1,Contact2,Contact3,Contact4

This sequence of records will be considered as 3 chunks and is allowed in single DML operation.

Execute below script and you will get this error:

List<sObject>  sbList=new List<sObject>();

for(integer i=0;i<10;i++){

    sblist.add(new Lead(lastname='Test Leat'+i,company='test company'+i));

    sblist.add(new Account(name='Test Account'+i));

    sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));

}

insert sblist;



Ways to resolve this kind of error:

  • Rearrange the records in list so that all records belonging to one object are stored together in list.

List<sObject>  sbList=new List<sObject>();
for(integer i=0;i<10;i++){
    sblist.add(new Lead(lastname='Test Leat'+i,company='test company'+i));
}
for(integer i=0;i<10;i++){
    sblist.add(new Account(name='Test Account'+i));
}
for(integer i=0;i<10;i++){
    sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));
}
insert sblist;

  • Sort the sobject list before performing DML

List<sObject>  sbList=new List<sObject>();
for(integer i=0;i<10;i++){
    sblist.add(new Lead(lastname='Test Leat'+i));
    sblist.add(new Account(name='Test Account'+i));
    sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));
}
sblist.sort();
insert sblist;

Hope this will help!!




Sunday, July 26, 2020

Compare CRUD (Object Level Access) Permission for a Profile from 2 different Org

Through this blog, I am going to share a script through which you can compare object level permission for a profile in 2 different SFDC orgs. This script is very helpful when you want to compare CRUD level permission for a profile in 2 different sandbox or permission in sandbox and production.

When you run below script, you will receive email with csv file with CRUD permission comparison.
You need to specify the target org domain url and sessionid or access_token of target org and need to run below script in source org in execute anonymous window in developer console.

Below is script:

Below is snapshot of csv file:



Note:

This is just a prototype and it may work for small organization. You need to consider heap size and apex CPU time limit exceeded errors. You can refractor this code for your use based on number of objects that you have in your org.

Hope this will help!!