Tuesday, December 14, 2021

How to dynamically determine Calling Context using Apex in Salesforce?

 

Batch - System.isBatch()

@future - System.isFuture()
Queueable - System.isQueueable()
Schedulable - System.isScheduled()
Trigger - Trigger.isExecuting


Visualforce - ApexPages.currentPage() != null
Apex REST - RestContext.request != null


Batch - System.isBatch() : 

How to prevent a trigger firing during a batch job?

I have a batch job that updates accounts. There is also an after trigger (just to make life more complicated). I want that the trigger will not fire during the batch job.


Sol:- You can use !system.isBatch() in your trigger to check if it is fired from within a batch or not.


USE OF TRIGGER.ISEXECUTING


 Trigger.isexecuting is used to identify that the current context for the Apex code is a trigger and the apex code is not getting called from any other sources like webservice, visualforce page, etc.

In simple words when we want our apex code to execute only when it is getting called from trigger we make use of trigger.isexecuting.

To understand this with an example we will be going to consider the below scenario.

SCENARIO: We are having the requirement to check if the phone number on the account record is getting updated with a new value and if it is getting updated we want the checkbox field(Phone Number Changed) on account record to be marked as true. Also, we want this piece of code in apex class to be fire only when the apex code is getting called from Trigger.

APEX TRIGGER:

trigger AccountMainTrigger on Account (before update) {
    createContactClass obj=new createContactClass();
    if(trigger.isbefore && trigger.isupdate)
    {
     obj.method1(trigger.new,trigger.old);
    }
}

APEX CLASS:

public class createContactClass {
       public void method1(List<Account> newList,List<Account> oldList){
             system.debug('Is trigger executing'+trigger.isexecuting);
                                            if(trigger.isexecuting){ // Checking If the current context for the apex code is a trigger.
                 for(Account newAcc:newList){
                     for(Account oldAcc:oldList){
                         if(newAcc.id==oldAcc.id){
                             if(newAcc.phone!=oldAcc.phone){
                                 newAcc.Phone_Number_Changed__c=True;
                             }
                         }
                     }
                 }
             }
       }
}



Trigger.isExecuting is to determine that your current context for the Apex code is a trigger, not a Visualforce page, a Web service, or an executeanonymous() API call.
Here is an example of Apex Class, this class can identify current context for the Apex code is a trigger using Trigger.isExecuting.

Apex Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AccountHandler
{
    public Boolean handleAccount(List<Account> accList){
         
        System.debug('Trigger is executing : ' + Trigger.isExecuting);
         
        if(Trigger.isExecuting){
            //Do what ever you want to do as part of the trigger invocation
        }
        else{
            //Do what ever you want to do if the call originated from different context, such as from controller.
        }
        return Trigger.isExecuting;
    }
}

Apex Trigger:

1
2
3
4
trigger AccountTrigger on Account (before insert, before update){
    AccountHandler handler = new AccountHandler();
    handler.handleAccount(Trigger.New);
}


Considerations for invoking a future method from trigger


While developing triggers, there might be a need to invoke a future method from the trigger to do certain things asynchronously (for eg., to make a callout, avoid MIXED_DML_OPERATION exception etc.,). In such instances, developers should make sure this invocation is not made if the current context is already asynchronous (ie., either future or batch).

Consider the following scenario. There is a trigger on Account object that invokes a future method as follows,

     trigger AccountTrigger on Account (after insert, after update) {                                                                            AccountHandler.makeCalloutFutureMethod(Trigger.newMap.keySet());
            }
* makeCalloutFutureMethod is a future annotated method
Now, if an Account record is inserted through a batch process or through another future method, the above trigger would throw an exception saying "CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountTrigger: execution of AfterInsert caused by: System.AsyncException: Future method cannot be called from a future or batch method". As the exception message indicates, a future method cannot be invoked from future or batch method execution context.

There are two possible workarounds for this problem:

Update the trigger logic to leverage the System.isFuture() and System.isBatch() calls so that the future method invocation is not made if the current execution context is future or batch. Records created through such cases should be handled separately using a scheduled batch job or something similar. The above example can be updated as follows,
        trigger AccountTrigger on Account (after insert, after update) {
            if(!System.isFuture() && !System.isBatch())                                                                                            AccountHandler.makeCalloutFutureMethod(Trigger.newMap.keySet());
                    }

 2. Replace the future method with Queueable Apex. Queueable Apex was introduced in Winter'15 and it is more powerful than future methods.

Please read the following articles to find more information about Queueable Apex: 

Tuesday, December 7, 2021

What is the use of Design Resource In Lightning Component Bundle

 

Design Resource In Lightning Component Bundle | Lightning Component Bundle Design Resources | What is the use of Design Resource




In this blog post we are going to talk about about "Design Resource In Lightning Component Bundle". A Lightning bundle includes following resources:-



What is the use of Design Resource:-
  • Its extension is ".design"
  • We use <design:attribute> to make lightning component attribute available for Admin to edit in Lightning Community/Lightning App Builder. With this Administrators can also change the component attributes as per client requirement.
  • Supported attribute of type : String, Boolean, Integer , Array (Picklist).

Here is Code:-

DesignResourceDemo.cmp


<aura:component implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes" access="global">
   
    <aura:attribute name="welcomeTitle" type="String" default="Welcome in Lightning" access="global" />
    <aura:attribute name="hideLogo" type="Boolean" default="true" access="global" />
    <aura:attribute name="LogoURL" type="String" default="https://c1.sfdcstatic.com/content/dam/web/en_us/www/images/home/logo-salesforce.svg" access="global" />
    <aura:attribute name="favoriteColors" type="String" default="Blue" access="global"/>
   
    <div class="header-section-top">
        <div class="slds-text-heading_large" style="{!'color:' + v.favoriteColors}" >
            {!v.welcomeTitle}
        </div>
       
        <aura:if isTrue="{!v.hideLogo}">
            <div class="header-section-top">
                <img src="{!v.LogoURL}" width="200" height="200" />
            </div>
        </aura:if>
    </div>
   
</aura:component>

DesignResourceDemo.design
 
<design:component>
    <design:attribute name="welcomeTitle" label="Welcome Title" />
    <design:attribute name="hideLogo" label="Hide Logo"/>
    <design:attribute name="LogoURL" label="URL" />
    <design:attribute name="favoriteColors" label="Color" datasource="Red,Black,White,Blue"/>
</design:component>

Output :-

Now With Design Resource Admin can change the Welcome Title,Logo , Image and Color of text.



NOTE:- You can create above picklist as dynamic as well.

You can test the same component from App Builder. Here is Demo.