Tuesday, January 8, 2019

Lightning Inter-Component Communication Patterns

Lightning Inter-Component Communication Patterns

If you’re comfortable with how a Lightning Component works and want to build production-grade applications for use in your org or to sell in AppExchange, this article is a must read. Understanding how a singular component works is important, but understanding how they work together is essential for building an effective application.
Interactive applications require components that can exchange data. In traditional HTML and JavaScript, this is straightforward as any script can modify the whole page. The modular nature of the Lightning Component Framework (LCF) requires more consideration for interactivity.
In line with best practices for security concerns, Lightning components are intentionally initially isolated from each other. By default, they’re safe from receiving or causing unwanted interference that can be exploited for malicious purposes. In practice, a Lightning component’s code cannot directly interact with its parent and vice versa. A parent component cannot manipulate its children or siblings as with standard JavaScript and the DOM. Inter-component communication must be specified by the developer.

In LCF, inter-component communication is supported in several well-defined ways. One can only use the following developer-defined interfaces to specify what can be exchanged:
  • Attributes or Methods to pass data down the component hierarchy
  • Lightning Events to pass data up and around in the component hierarchy

Passing data down the component hierarchy

Attributes

Attributes are the most commonly used element to pass data down the component hierarchy as they are simple to use. In order to pass data down from a parent component to its child, simply use the following code:
Parent component
<aura:component>
   <aura:attribute name="parentAttribute" type="String"/> 
   <c:childComponent childAttribute="{!v.parentAttribute}"/>
</aura:component>
Child component

<aura:component>
   <aura:attribute name="childAttribute" type="String"/> 
</aura:component>
In this example, the parent component value of parentAttribute is transferred to the childAttribute of the child component via the {!v.parentAttribute} expression.
This is perfect if you just want to display the data in a child component. What about if you also want to execute some logic when the attribute’s value changes?
Consider the following updated definition of childComponent :
<aura:component>
   <aura:attribute name="childAttribute" type="String"/> 
   <aura:handler name="change" value="{!v.childAttribute}" action="{!c.onChildAttributeChange}"/>
</aura:component>
With the addition of a change handler, the child component can now trigger the onChildAttributeChangecontroller function automatically when the value of childAttribute changes. This allows us to implement some custom logic such as:

({
    onChildAttributeChange : function (component, event, helper) {
        console.log("Old value: " + event.getParam("oldValue"));
        console.log("Current value: " + event.getParam("value"));
    }
})
We now have established a top-down communication chain between the parent and the child component. This can be summarized in these few steps:
  1. parentAttribute value changes
  2. parentAttribute value is transferred to childAttribute
  3. childComponent’s change handler triggers the onChildAttributeChange controller function
This approach works great for processing an attribute. What about multiple attribute changes? If you want to change two or more attributes and then trigger some logic, this method becomes unwieldy. You can either combine the attributes into a larger object (not always practical) or write a complex synchronization algorithm (please don’t). Instead, I recommend methods for multiple attribute changes.

Methods

Based on frequent exchanges with the developer community, I have gathered that methods tend to be overlooked in favor of attributes. However, I have found methods to be quite flexible, as they allow users to create and expose component APIs.
Let’s look at an example involving two components communicating with a method. Here we have a child component that exposes a myMethod method with two parameters (param1 and param2).
<aura:component>
    <aura:method name="myMethod" action="{!c.executeMyMethod}"> 
        <aura:attribute name="param1" type="String"/> 
        <aura:attribute name="param2" type="String"/> 
    </aura:method>
</aura:component>
myMethod is hooked to an executeMyMethod function in the component’s controller:

({
    executeMyMethod : function (component, event, helper) {
        var params = event.getParam('arguments');
        console.log('Param 1: '+ params.param1);
        console.log('Param 2: '+ params.param2);
    }
})
This function retrieves the arguments (param1 and param2) passed to myMethod and outputs them in the console. Note that the arguments key used in event.getParam is a constant.
Let’s now look at the parent component. It has two attributes (parentAttribute1 and parentAttribute2), a reference to the child component, and a button.
<aura:component>
    <aura:attribute name="parentAttribute1" type="String" default="A"/>
    <aura:attribute name="parentAttribute2" type="String" default="B"/>
    <c:childComponent aura:id="child"/>
    <lightning:button label="Call child method" onclick="{! c.onCallChildMethod }" />
</aura:component>
When clicked, the button calls a onCallChildMethod function in the component’s controller. This function retrieves the value of the two attributes and retrieves the child component by using its aura:id. It then calls a myMethodmethod on the child component and passes the two attribute values as parameters.
({
    onCallChildMethod : function(component, event, helper) {
        var attribute1 = component.get('v.parentAttribute1');
        var attribute2 = component.get('v.parentAttribute2');
        var childComponent = component.find('child');
        childComponent.myMethod(attribute1, attribute2);
    }
})
If we now step back and look at the big picture, here’s what happens:
  1. When the parent component button is clicked, the onCallChildMethod controller function of parentComponent is called
  2. onCallChildMethod retrieves a reference to childComponent using find with an aura:id
  3. onCallChildMethod calls the myMethod method of childComponent
  4. myMethod triggers the executeMyMethod controller function of childComponent
This “method” approach is quite powerful as users can pass data to a child component and perform some operations once this is done. Users can also create distinct methods involving the same arguments but triggering different functions. Finally, developers get the benefit of clarity by exposing named methods that—hopefully—reflect their intended behavior.
Achieving all of this is not possible by just passing attributes from parent to child components.

Passing data up and around the Lightning component hierarchy

The way to pass data up and around in the Lightning component hierarchy is to use events. There are two types of events that users can employ for that purpose: application events and component events.
There are some minor syntax differences between these two types of events, but we do not discuss them in this article for the sake of brevity. Instead, we focus on their propagation mechanisms, which in turn dictates their use cases.

Application Events

Application events are broadcast to all Lightning components that are registered as listeners for that specific event.
If we look at the example described in the schema on the right, here’s what happens:
  1. A component fires an application event.
  2. All other components can handle the event provided that they have registered the appropriate event handler.
All event handlers are triggered simultaneously. There is no way to cancel an application event once fired.
Application events are great for supporting business logic events as they are quite flexible: They do not impose a particular architecture. This is ideal when building components that are exposed in the Lightning App Builder. However, bear in mind that this flexibility comes at the expense of performance in certain use cases due to the event broadcast.
For example, it can be expensive to use an application event for a fine-grained component such as a button to notify other components that it is clicked. Your event will be sent to all of the components. They have to identify the source of the event then, verify if they handle it. Typically all components except one are registered to handle the event. Conversely, if you use an application event for a coarse-grained event in the App Builder that two other components may listen to, there is no performance impact.

Component Events

Component events are “clones” of standard DOM events (mouse clicks, key press, and so on). Just like their DOM counterparts, they propagate up in the component hierarchy via a bubbling mechanism and can be stopped en route to the application root component.
Here is an example of such a behavior:
  1. Component E fires a component event.
  2. Event bubbles to E’s direct parent: component D.
  3. Component D can handle the event or not and optionally prevent its propagation by capturing it.
  4. If Component D did not capture the event, it propagates to A (this applies even if D did not handle the event).
  5. Component B and C do not handle the event, as they are not in the ancestry line of E.
The advantage of component events is that you know their maximum scope in advance (all parent components) and you have some degree of control over it (you can capture the event along the way).

Advanced event architecture

As a rule, consider using a component event before employing an application event. These are more common and usually have little effect on performance. However, when facing a blocking use case or an overly complex architecture, think about going for an application event.
Consider using a component event for handling low-level UI interactions such as selections and form validation. You can then combine these with application events that handle “business” events. This integrates into a larger architecture via a central “dispatcher” component such as this:

Closing words

In this article we covered Lightning inter-component communication options. You learned about passing data down the component hierarchy with attributes and methods. You also had an overview of the different event types with their use cases and limitations. You are now ready to build a larger Lightning project with a robust architecture that you can quickly deploy to production. If you have any questions, reach out to our community’s Stack Exchange.

Code samples

Here are some working code samples covering the inter-component communication patterns presented in this post:

Wednesday, November 22, 2017

Data Loader vs Batch Apex

Basically Apex data loader is a desktop tool and it is meant for data migration between two systems. In other words, when you want to move data between SFDC and some other environment, you go with data loader.
Say like you want to take a weekly backup of the account object and store it on your desktop, then you can use data loader.

Batch Apex is meant for processing of bulk data within SFDC. It should be used when you have some logic that you want to apply on large data volumes within SFDC, but has nothing to do with an external environment.
Say like you want to send an email to all users who have not logged in in the past month, you can use batch apex (assuming your user volume is BIG).

1) Data Loader is used to export/insert/update/delete data in your organisation,
anything that a person does manually i,e. prepare a sheet and load the data given by client etc

Its just a tool to interact with your database and do manipulations

Whereas Batch Apex is apex code which will include your custom logic and do the data manipulations in bulk. Via batch apex you can automate the data processing with very strong level of flexibility.

2) Bulk API is as name suggest is an API which allows you to load data in millions within less duration of time using parallel asych processing

Data loader can be configured to use Bulk API when you have data in huge amount!

For More information:

https://developer.salesforce.com/forums/?id=906F000000092wuIAA

https://success.salesforce.com/answers?id=90630000000giHyAAI

https://success.salesforce.com/answers?id=90630000000gjCfAAI

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Data Loader:

Data Loader is a client application for the bulk import or export of data. Use it to insert, update, delete, or export Salesforce records. When importing data, Data Loader reads, extracts, and loads data from comma separated values (CSV) files or from a database connection. When exporting data, it outputs CSV files.

The Data Loader is an easy to use graphical tool that helps you to get your data into Salesforce objects. The Data Loader can also be used to extract data from database objects into any of the destinations mentioned above. You can even use the Data Loader to perform bulk deletions by exporting the ID fields for the data you wish to delete and using that source to specify deletions through the Data Loader.

The Data Loader requires the use of the Force.com API. If your Salesforce edition allows the use of the API (Enterprise, Unlimited and Developer Editions), you can download the Data Loader from the Setup menu, under Administer heading - Data Management.

Please go through some of the links below:

https://developer.salesforce.com/page/Data_Loader

https://help.salesforce.com/apex/HTViewHelpDoc?id=data_loader.htm&language=en

https://help.salesforce.com/apex/HTViewHelpDoc?id=inserting_updating_or_deleting_data.htm&language=en

https://www.youtube.com/watch?v=8azP1kuf9IQ

https://www.youtube.com/watch?v=rjuFthPE3jY

Batch Apex:

Batch Apex is mainly to process the existing salesforce records based on certain criteria.
A Batch class allows you to define a single job that can be broken up into manageable chunks that will be processed separately.

When to use Batch Apex
One example is if you need to make a field update to every Account in your organization. If you have 10,001 Account records in your org, this is impossible without some way of breaking it up. So in the start() method, you define the query you're going to use in this batch context: 'select Id from Account'. Then the execute() method runs, but only receives a relatively short list of records (default 200). Within the execute(), everything runs in its own transactional context, which means almost all of the governor limits only apply to that block. Thus each time execute() is run, you are allowed 150 queries and 50,000 DML rows and so on. When that execute() is complete, a new one is instantiated with the next group of 200 Accounts, with a brand new set of governor limits. Finally the finish() method wraps up any loose ends as necessary, like sending a status email.

Sample Batch Apex
1) Start method is automatically called at the beginning of the apex job. This method will collect record or objects on which the operation should be performed. These record are divided into subtasks & passes those to execute method.

2) Execute Method performs operation which we want to perform on the records fetched from start method.

3) Finish method executes after all batches are processed. Use this method to send confirmation email notifications.

Please go through the below links for more information:

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

https://developer.salesforce.com/docs/atlas.en-us.apex_workbook.meta/apex_workbook/apex_batch_intro.htm

http://www.infallibletechie.com/2013/01/simple-batch-apex-example-in-salesforce.html

http://www.salesforcetutorial.com/what-is-batch-apex/

http://www.salesforcetutorial.com/running-batch-apex-example/

https://www.youtube.com/watch?v=PmvpMakxpm8

http://blog.shivanathd.com/2013/01/how-to-write-batch-class-in.html

http://amitsalesforce.blogspot.com/2016/02/batch-apex-in-salesforce-test-class-for.html

https://www.minddigital.com/how-to-call-batch-apex-by-scheduler-class-within-salesforce/

Friday, November 17, 2017

Using the final Keyword

Using the final Keyword

You can use the final keyword to modify variables.Final variables can only be assigned a value once, either when you declare a variable or inside a constructor. You must assign a value to it in one of these two places.
Static final variables can be changed in static initialization code or where defined.Member final variables can be changed in initialization code blocks, constructors, or with other variable declarations.
To define a constant, mark a variable as both static and final.Non-final static variables are used to communicate state at the class level (such as state between triggers). However, they are not shared across requests.
Methods and classes are final by default. You cannot use the final keyword in the declaration of a class or method. This means they cannot be overridden. Use the virtual keyword if you need to override a method or class.

Thursday, November 16, 2017

Sample Trigger Scenarios of Salesforce

Trigger Scenario 1:

Create “Top X Designation” custom object which is the related list to Opportunity (Look up Relationship). In the Top X Designation object, create the fields
  • Type (Picklist),
  • Document Attached (Checkbox)
Create one field Handoff Attached with pick list type with values are Yes, No on Opportunity Object.
Logic :-  If Type (Top X Designation) = “Contract Flow Down/Handoff”, and “Document Attached” = True then “Handoff Attached” = True, otherwise false.
Code:-
trigger UpdateHandoffAttached on Top_X_Designation__c(after insert, after update,
 after delete) {
 List<Opportunity> listoppUpdate=new List<Opportunity>();
 List<Opportunity> listopp=new List<Opportunity>();
 Set<Id> setOppId=new Set<Id>();
 Set<Id> setOppDelete=new Set<Id>();
 map<id,id> mapDocAttchTrue = new map<id,id>();
 map<id,id> mapDocAttchFalse = new map<id,id>();
 map<id,id> mapDelete = new map<id,id>();
 if(Trigger.isInsert || Trigger.isUpdate){
 for(Top_X_Designation__c ada:Trigger.New){
 if(ada.Document_Attached__c==True && ada.Item_Type__c=='Contract Flow
 Down/Handoff'){
 mapDocAttchTrue.put(ada.Opportunity,ada.id);
 setOppId.add(ada.Opportunity);
 }
 else
 mapDocAttchFalse.put(ada.Opportunity,ada.id);
 setOppId.add(ada.Opportunity);
 }
 }
 if(Trigger.isDelete){
 for(Top_X_Designation__c ada:Trigger.old){
 mapDelete.put(ada.Opportunity,ada.id);
setOppId.add(ada.Opportunity);
 setOppDelete.add(ada.Opportunity);
 }
 }
 listopp = “select id,Handoff_Attached__c from Opportunity where id in: setOppId”;
 if(listopp.size()>0 && listopp !=null){
 for(Opportunity opp:listopp){
 if(mapDocAttchTrue.containskey(opp.id)){
 opp.Handoff_Attached__c='Yes';
 }
 if(mapDocAttchFalse.containskey(opp.id)){
 opp.Handoff_Attached__c='No';
 }
 if(setOppDelete.contains(opp.id)){
 opp.Handoff_Attached__c='';
 }
 listoppUpdate.add(opp);
 }
 }
 if(listoppUpdate.size()>0 && listoppUpdate!=null){
 update listoppUpdate;
 system.debug('LLLLLLLLLLLLLLL'+listoppUpdate);
 }
 }

Trigger Scenario 2:-

The following Trigger will fires when we try to create the account with same name i.e. Preventing the users to create Duplicate Accounts
trigger AccountDuplicateTrigger on Account (before insert, before update)
{
 for(Account a:Trigger.new)
 {
 List<Account> acc=“Select id from Account where Name=:a.Name and Rating=:a.Rating
 “;
 if(acc.size()>0)
 {
 acc.Name.addError('You Cannot Create the Duplicate Account');
 }
 }
 }

Trigger Scenario 3:-

The following trigger updates the field called “Hello” by the value “World” whenever we are creating an account or updating an account record. Create the field called “Hello” on the Account Object (Data Type = Text)
trigger HelloWorld on Account (before insert, before update)
{
 List<Account> accs = Trigger.new;
 MyHelloWorld my= new MyHelloWorld(); //creating instance of apex class
 my.addHelloWorld(accs); // calling method from the apex class
 }
Class:
public class MyHelloWorld
 {
 public void addHelloWorld(List<Account> accs)
 {
 for (Account a:accs)
 {
 if (a.Hello__c != 'World')
 {
 a.Hello__c = 'World';
 }
 }
 }
 }

Trigger Scenario 4:-

The following trigger describes when the leads are inserted into the data base it would add Doctor prefixed for all lead names. This is applicable for both inserting and updating the lead records.
trigger PrefixDoctor on Lead (before insert,before update)
{
 List<Lead> leadList = trigger.new;
 for(Lead l: leadList)
 {
 l.firstname = 'Dr.'+ l.firstname;
 }
 }

Trigger Scenario 5:-

The following trigger adds the Opportunity Owner into the sales team automatically whenever the Opportunity is created.
trigger OppTeam on Opportunity (after insert) {
 List<OpportunityShare> sharesToCreate = new List<OpportunityShare>();
 List<OpportunityTeamMember> oppteam = new List<OpportunityTeamMember
 > ();
 OpportunityShare oshare = new OpportunityShare();
 oshare.OpportunityAccessLevel = 'Edit';
 oshare.OpportunityId = trigger.new”0”.Id;
 oshare.UserOrGroupId = trigger.new”0”.createdbyid;
 sharesToCreate.add(oshare);
 OpportunityTeamMember ot = new OpportunityTeamMember();
 ot.OpportunityId = trigger.new”0”.Id;
 ot.UserId = trigger.new”0”.OwnerId;
 ot.TeamMemberRole = 'Account Manager';
 oppteam.add(ot);
 if(Oppteam!=null && Oppteam.size()>0)
 {
 insert Oppteam;
 }
 if(sharesToCreate!=null && sharesToCreate.size()>0)
 {
 list<Database.SaveResult> sr = Database.insert(sharesToCreate,false);
}
 }

Trigger Scenario 6:-

Create the object called “Books” and create field “Price”(data type is Currency) under this object.
Whenever we enter some amount of money in the Price field and once we click on save
button, the value we entered in the Price field is 10% less than the actual price. This is
applicable for while both inserting and updating records.
trigger DiscountTrigger on Book__c (before insert, before update) {
 List<Book__c> books = Trigger.new;
 PriceDiscount.applyDiscount(books);
 }
  [1]
Class
public class PriceDiscount {
 public static void applyDiscount(List<Book__c> books) {
 for (Book__c b :books){
 b.Price__c *= 0.9;
 }
 }
 }

Trigger Scenario 7:-

The following trigger will prevent the users from deleting the Accounts. This is because System Administrator has all the permissions, we cannot change the permissions.
trigger AccountDelete on Account (before delete) {
 for(Account Acc:trigger.old)
 {
 acc.adderror('You Cannot Delete the Account Record');
 }
 }

Trigger Scenario 8:-

Create Custom field called “Number of Locations” on the Account Object (Data Type=Number)
The following trigger creates the number of contacts which are equal to the number which we will enter in the Number of Locations field on the Account Object
Code:
trigger ContactsCreation on Account (after insert) {
 list<contact> listContact = new list<contact>();
 map<id,decimal> mapAcc=new map<id,decimal>();
 for(Account acc:trigger.new){
 mapAcc.put(acc.id,acc.Number_of_Locations__c);
 }
 if(mapAcc.size()>0 && mapAcc!=null){
 for(Id accId:mapAcc.keyset()){
 for(integer i=0;i<mapAcc.get(accId);i++){
 contact newContact=new contact();
 newContact.accountid=accId;
 newContact.lastname='contact'+i;
 listContact.add(newContact);
 }
 }
 }
 if(listContact.size()>0 && listContact!=null)
 insert listContact;
 }

Trigger Scenario 9:-

Create the object called “Customer Project” and create Status field under this object with picklist data type (Values=Active, Inactive). Create the relationship between this custom object and Opportunity so that Customer Project is related list to the Opportunity.
Create  Active Customer project‑ field on Opportunity object (Data Type=Checkbox)
The logic is when we create Customer Project for an Opportunity with the Status=Active, then Active Customer project check box on the Opportunity Detail page is automatically
checked.
Code:-
trigger UpdateCPActivenOnOppty on Customer_Project__c (after insert)
 {
 List<Opportunity> opps=new List<Opportunity>();
 for(Customer_Project__c cp:Trigger.New){
 if(cp.Status__c=='Active'){
 Opportunity opp= new Opportunity(id=cp.Opportunity__c);
 opp.Active_Customer_Project__c = True;
 opps.add(opp);
 }
 }
 update opps;
 }

Trigger Scenario 10:-

Description:
We have Stakeholder object that is the related list to Opportunity and Contact. On Contact detail page, we have NPS ID field on the Contact detail page that is look up to the Voice of NPS object (Customer Object). The following code will get the NPS ID field value from the Contact detail page in the Stackholders page which we can able to clickable.
Create NPS Id 1 field on the stackholders object which is the look up to the Voice of NPS object (Customer Object)
Note:-
‑ we can also get the NPS Id 1 on the Stakeholder’s page using the formula field but will not able to clickable.
Code Single Record:-
triggerUpdateNPSid on Stakeholder__c (before insert, before update){
 List<id>ConList=new List<id>();
 for(Stakeholder__csh:Trigger.New){
ConList.add(sh.Contact_Name__c);
 }
 List<Contact>lc=“Select NPS_Id__c From Contact Where id IN : ConList”;
 for(Stakeholder__csh:Trigger.New){
 sh.NPS_Id1__c=lc”0”.NPS_Id__c;
 }
 }
Code Bulk Records:-
trigger UpdateNPSid on Stakeholder__c (before insert, before update){
 List<id> ConList=new List<id>();
 map<id,id>map_NPS_Cont = new map<id,id>();
 for(Stakeholder__c sh:Trigger.New)
 {
 if(sh.Contact_Name__c!=null)
 ConList.add(sh.Contact_Name__c);
 }
 List<Contact> lc=“Select Id,NPS_Id__c From Contact Where id IN : ConList”;
 if(lc!=null && lc.size()>0)
 {
 for(Contact c:lc){
 If(c.NPS_Id__c!=null){
 map_NPS_Cont.put(c.Id,c.NPS_Id__c);
 }
 }
 for(Stakeholder__c sh:Trigger.New){
 if(sh.Contact_Name__c!=null)
 sh.NPS_Id1__c = map_NPS_Cont.get(sh.Contact_Name__c);
 else
 sh.NPS_Id1__c = null;
 }
 }
 }

Trigger Scenario 11:-

Create “Sales Rep” field with data type (Text) on the Account Object. When we create the Account record, the Account Owner will be automatically added to Sales Rep field. When we update the Account owner of the record, then also the Sales Rep will be automatically updated.
triggerUpdateSalesRep on Account (Before insert,Before Update){
 Set<Id>setAccOwner=new Set<Id>();
 for(Account Acc: trigger.new)
 {
 setAccOwner.add(Acc.OwnerId);
 }
 Map<Id,User>User_map = new Map<Id,User>(“select Name from User where id
 in:setAccOwner”);
 for(Account Acc: Trigger.new)
 {
 User usr=User_map.get(Acc.OwnerId);
 Acc.sales_Rep1__c=usr.Name;
 }
 }

Trigger Scenario 12:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the related object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Now logic is when we create contact by checking Contact Relationship checkbox, then Contact Relationship will be created automatically for that contact.
Code:
trigger CreateCRonContactCreation on Contact (after insert) {
 if(trigger.isAfter)
 {
 if(trigger.isInsert)
 {
 ContactMasterHandler ConIns = New ContactMasterHandler();
 ConIns.createContactRelationshipByContact(trigger.New);
}
 }
 }
Class:
Public Class ContactMasterHandler {
 public void createContactRelationshipByContact(list<Contact> List_Contacts)
 {
 list<Contact_Relationship__c> ConList= new list<Contact_Relationship__c>();
 for(Contact newconts:List_Contacts)
 {
 if(newconts.Contact_Relationship__c== true)
 {
 Contact_Relationship__c CR = new Contact_Relationship__c();
 CR.Name=newconts.Lastname;
 CR.Contact__c= newconts.id;
 ConList.add(CR);
 }
 }
 insert ConList;
 }

Trigger Scenario 13:-

When we change the Owner of the Contact Relationship, then the Owner name will be automatically populated in the Contact Relationship Name field.
Trigger:
trigger ContactRelationshipMasterTrigger on Contact_Relationship__c(before update)
 {
 if(trigger.isBefore)
 {
 if(trigger.isUpdate)
 {
 //call the handler for the before update trigger event
 updateCROwnerName ConRelUpd = New updateCROwnerName();
 ConRelUpd.updateContactRelationshipNameByOwner(trigger.New);
 }
 }
 }
Class:
Public Class updateCROwnerName{
 public void updateContactRelationshipNameByOwner(list<Contact_Relationship__c> co
 nt_Rel)
 {
 map<Id,Id> map_Id_Own = new map<id,id>();
 map<Id,string> map_id_Name = new map<id,string>();
 set<id> Idset = new set<id>();
 for(Contact_Relationship__c List_recs:cont_Rel)
 {
 Idset.add(List_recs.Ownerid);
 }
 list<user> u=“select id,Name from user where id in:Idset”;
 for(user list_users:u)
 {
 map_id_Name.put(list_users.Id,list_users.Name);
 }
 if(u!=null && u.size()>0)
 {
 for(Contact_Relationship__c List_recs:cont_Rel)
 {
 if (List_recs.Ownerid!=null)
 {
 List_recs.Name = map_id_Name.get(List_recs.Ownerid);
 }
 }
 }
 }
 }

Trigger Scenario 14:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Trigger Scenario 12 logic will says that when we create contact by checking Contact Relationship checkbox, then Contact Relationship will be created automatically for that contact.
No this logic will for when we delete the Contact, Then Contact Relationship will be deleted automatically
 trigger DeleteCRonContactDeletion on Contact (before delete) {
 if(trigger.isBefore)
 {
 if(trigger.isDelete)
for(Contact c:Trigger.old)
 {
 Contact_relationship__c CR=new Contact_relationship__c();
 CR=“Select Id from Contact_Relationship__c where Contact__c IN:GlobalUtility.getUni
 queIds(Trigger.Old)”;
 delete CR;
 }
 }
 }
 }
Global Utility Classs:
public static set<Id> getUniqueIds(list<SObject> sobs)
 {
 set<Id> Ids = new set<Id>();
 for (SObject sob : sobs) {
 Ids.add(sob.Id);
 }
 return Ids;
 }

Trigger Scenario 15:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Trigger Scenario 14 will says that when we delete the Contact, Then Contact Relationship will be deleted automatically
Now the Logic is when we undelete the Contact, then Contact Relationship will be undeleted automatically
Triggser:
trigger UnDeleteCRonContactUnDeletion on Contact (After Undelete) {
 if(trigger.isUndelete)
 {
//call the handler for the after undelete trigger event
 ContactMasterHandler_Undelete ConIns = New ContactMasterHandler_Undelete(
 );
 ConIns.undeleteContactRelationshipsByContact(Trigger.New);
 }
 }
Class
Public Class ContactMasterHandler_Undelete{
 public void undeleteContactRelationshipsByContact(list<Contact> List_Contacts)
 {
 set<Id> ContactIds = New set<Id>();
 if(List_Contacts!=null && List_Contacts.size()>0)
 {
 list<Contact_Relationship__c> List_ConRels= new list<Contact_Relationship__c>(
 );
 List_ConRels= “select id from Contact_Relationship__c where isDeleted=TRUE and Co
 ntact__c in: GlobalUtility.getUniqueIds(List_Contacts)”;
 undelete List_ConRels;
 }
 }
 }

Trigger Scenario 16:-

Create field called “Count of Contacts” on Account Object. When we add the Contacts for that Account then count will populate in the field on Account details page. When we delete the Contacts for that Account, then Count will update automatically.
Inclined towards the profession of the Salesforce? 
Then what is the waiting for.. study the blog post on Salesforce Training to master the skill.
Note:
The above logic will be applicable when we have look up relationship. But When we have the Master – Detail relationship, then we can create Rollup Summary field to get the count of child records using “Count” function.
trigger CountOfContacts on Contact (after insert,after delete) {
 set<id> accid=new set<id>();
 list<contact> contactlist =new list<contact>();
 list<contact> listcon=new list<contact>();
 list<account> acclist=new list<account>();
 list<account> listAcc=new list<account>();
map<id,integer> mapCount=new map<id,integer>();
 if(trigger.isinsert){
 for(contact con:trigger.new){
 accid.add(con.accountid);
 }
 }
 if(trigger.isdelete){
 for(contact con:trigger.old){
 accid.add(con.accountid);
 }
 }
 acclist=“select id,name from account where id in:accid”;
 contactlist = “select id,name,accountid from contact where accountid in:accid”;
 for(account acc:acclist){
 listcon.clear();
 for(contact c:contactlist){
 if(c.accountid==acc.id){
 listcon.add(c);
 mapCount.put(c.accountid,listcon.size());
 }
 }
 }
 if(acclist.size()>0){
 for(Account a:acclist){
 if(mapCount.get(a.id)==null)
 a.Count_Of_Contacts__c=0;
else
 a.Count_Of_Contacts__c=mapCount.get(a.id);
 listAcc.add(a);
 }
 }
 if(listAcc.size()>0)
 update listAcc;
 }

Trigger Scenario 17:-

Create the object called “Customer” and create the Master-Detail Relationship on Customer object so that Customer will be the related list to Account record. Create the field called “Account Manager” on Customer object which is lookup to the user object.
Now Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Code:
trigger InsertAccountTeam on Customer__c (after insert) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isInsert)
 {
 For(Customer__c c:Trigger.new)
 {
 if(c.Account_Manager__c!=null){
 atm = new AccountTeamMember();
 atm.accountid=c.Account__c;
 atm.teamMemberRole='Account Manager';
atm.UserId=c.Account_Manager__c;
 AccountShare shares = new AccountShare();
 shares.AccountId=c.Account__c;
 shares.UserOrGroupId = c.Account_Manager__c;
 shares.AccountAccessLevel='Read/Write';
 shares.OpportunityAccessLevel = 'Read Only';
 shares.CaseAccessLevel='Read Only';
 newShare.add(shares);
 atm_list.add(atm);
 }
 }
 if(atm_list!=null)
 insert atm_list;
 if(newShare!=null && newShare.size()>0)
 List<Database.saveresult> sr=Database.insert(newShare,false);
 }
 }

Trigger Scenario 18:-

The above trigger(Trigger Scenario 17) Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Now the following trigger logic is when we update the user in the “Account Manager”, the Account team will be updated automatically.
Code:
trigger UpdateAccountTeam on Customer__c (before update) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isupdate)
 {
 if(trigger.isbefore)
 {
 Set<Id> setAccIds1=new Set<Id>();
 Set<Id> setDelATM=new Set<Id>();
 Map<id,Set<Id>> mapAccMgrs=new Map<id,Set<Id>>();
 for(Customer__c c:Trigger.new)
 {
 if(trigger.oldmap.get(c.Id).Account_Manager__c!=c.Account_Manager__c
 &&c.Account_Manager__c!=null )
 {
 setAccIds1.add(c.Account__c);
 }
 }
 List<Customer__c> listPLAccMgrs=“select id,Account_Manager__c,Account__c
 from Customer__c where Account__c in:setAccIds1 and id not
 in:trigger.newmap.keyset()”;
 if(listPLAccMgrs!=null && listPLAccMgrs.size()>0)
 {
 for(Customer__c c:listPLAccMgrs)
 {
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(null==idMgrs){
 idMgrs=new set<Id>();
 mapAccMgrs.put(c.Account__c,idMgrs);
 }
 idMgrs.add(c.Account_Manager__c);
 }
 }
 Map<id,List<AccountTeamMember>> mapStdAccTeam=new
 Map<id,List<AccountTeamMember>>();
 List<AccountTeamMember> listStdAcc Team=“select id,UserId,AccountId from
 AccountTeamMember where AccountId in:setAccIds1 “;
 if(listStdAccTeam!=null && listStdAccTeam.size()>0){
 for(AccountTeamMember recAccTeam :listStdAccTeam)
 {
 List<AccountTeamMember>
 listStdAccTeamMap=mapStdAccTeam.get(recAccTeam.AccountId);
 if(null==listStdAccTeamMap){
 listStdAccTeamMap=new List<AccountTeamMember>();
 mapStdAccTeam.put(recAccTeam.AccountId,listStdAccTeamMap);
 }
 listStdAccTeamMap.add(recAccTeam);
 }
 }
 system.debug('***********'+mapAccMgrs);
 for(Customer__c c:Trigger.new)
 {
 if(trigger.oldmap.get(c.Id).Account_Manager__c!=c.Account_Manager__c
 &&c.Account_Manager__c!=null )
 {
 List<AccountTeamMember>
 listAccTeam=mapStdAccTeam.get(c.Account__c);
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(listAccTeam!=null && listAccTeam.size()>0 )
{
 if(idMgrs!=null && idMgrs.size()>0 &&
 !(idMgrs.Contains(trigger.oldmap.get(c.Id).Account_Manager__c)))
 {
 for(AccountTeamMember recATM:listAccTeam)
 {
 if(recATM.UserId==trigger.oldmap.get(c.Id).Account_Manager__c)
 setDelATM.add(recATM.Id);
 }
 }
 else if(idMgrs==null)
 {
 for(AccountTeamMember recATM:listAccTeam)
 setDelATM.add(recATM.Id);
 }
 }
 atm = new
 AccountTeamMember(accountid=c.Account__c,teamMemberRole='Account
 Manager',UserId=c.Account_Manager__c);
 AccountShare shares = new AccountShare();
 shares.AccountId=c.Account__c;
 shares.UserOrGroupId = c.Account_Manager__c;
 shares.AccountAccessLevel='Edit';
 shares.OpportunityAccessLevel = 'None';
 newShare.add(shares);
 atm_list.add(atm);
 }
 }
List<AccountTeamMember> listDelATM=“select id from AccountTeamMember
 where id in:setDelATM”;
 if(listDelATM!=null && listDelATM.size()>0 )
 delete listDelATM;
 if(atm_list!=null)
 insert atm_list;
 if(newShare!=null && newShare.size()>0)
 List<Database.saveresult> sr=Database.insert(newShare,false);
 }
 }

Trigger Scenario 19:-

The trigger scenario 17 Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Now the following trigger gives the logic about when we delete the “Customer” of that account, then the user will deleted automatically from the Account Team of that account.
trigger DeleteAccountTeam on Customer__c (before delete) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isdelete)
 {
set<id> setAccids = new set<id>();
 Set<Id> setDelATM=new Set<Id>();
 Map<id,Set<Id>> mapAccMgrs=new Map<id,Set<Id>>();
 for(Customer__c c:Trigger.old)
 {
 setAccids.add(c.Account__c);
}
 List<Customer__c> listPLAccMgrs=“select id,Account_Manager__c,Account__c from
 Customer__c where Account__c in:setAccids and id not in:trigger.oldmap.keyset()”;
 if(listPLAccMgrs!=null && listPLAccMgrs.size()>0)
 {
 for(Customer__c c:listPLAccMgrs)
 {
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(null==idMgrs){
 idMgrs=new set<Id>();
 mapAccMgrs.put(c.Account__c,idMgrs);
 }
 idMgrs.add(c.Account_Manager__c);
 }
 }
 Map<id,List<AccountTeamMember>> mapStdAccTeam=new
 Map<id,List<AccountTeamMember>>();
 List<AccountTeamMember> listStdAccTeam=“select id,UserId,AccountId from
 AccountTeamMember where AccountId in:setAccids”;
 if(listStdAccTeam!=null && listStdAccTeam.size()>0){
 for(AccountTeamMember recAccTeam :listStdAccTeam)
 {
 List<AccountTeamMember>
 listStdAccTeamMap=mapStdAccTeam.get(recAccTeam.AccountId);
 if(null==listStdAccTeamMap){
 listStdAccTeamMap=new List<AccountTeamMember>();
 mapStdAccTeam.put(recAccTeam.AccountId,listStdAccTeamMap);
 }
 listStdAccTeamMap.add(recAccTeam);
}
 }
 for(Customer__c c:Trigger.old)
 {
 List<AccountTeamMember>
 listAccTeam=mapStdAccTeam.get(c.Account__c);
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(listAccTeam!=null && listAccTeam.size()>0 )
 {
 if(idMgrs!=null && idMgrs.size()>0 &&
 !(idMgrs.Contains(trigger.oldmap.get(c.Id).Account_Manager__c)))
 {
 for(AccountTeamMember recATM:listAccTeam)
 {
 if(recATM.UserId==trigger.oldmap.get(c.Id).Account_Manager__c)
 setDelATM.add(recATM.Id);
 }
 }
 else if(idMgrs==null)
 {
 for(AccountTeamMember recATM:listAccTeam)
 setDelATM.add(recATM.Id);
 }
 }
 }
 List<AccountTeamMember> listDelATM=“select id from AccountTeamMember
 where id in:setDelATM”;
if(listDelATM!=null && listDelATM.size()>0 )
 delete listDelATM;
 }
 }

Trigger Scenario 20:-

When we create the Opportunity with the Probability=20, then the opportunity owner will be automatically added to Account Team of the associated account for that Opportunity.
Code:
trigger UpdateATMwithOwneronOptyCreate on Opportunity (after insert,after update) {
 List<AccountShare> list_share= new List<AccountShare>();
 List<AccountTeamMember> list_atm=new List<AccountTeamMember>();
 for(Opportunity opp:Trigger.New)
 {
 if(opp.Probability==20)
 {
 AccountTeamMember atm=new AccountTeamMember();
 atm.accountid=opp.accountid;
 atm.teamMemberRole='Account Manager';
 atm.UserId=opp.Ownerid;
 AccountShare share = new AccountShare();
 share.AccountId=opp.Accountid;
 share.UserOrGroupId = opp.OwnerId;
 share.AccountAccessLevel='Read/Write';
 share.OpportunityAccessLevel = 'Read Only';
 share.CaseAccessLevel='Read Only';
 list_atm.add(atm);
 list_share.add(share);
 }
 }
 if(list_atm!=null)
 insert list_atm;
 if(list_share!=null && list_share.size()>0)
 List<Database.saveresult> sr=Database.insert(list_share,false);
Technology:
In the above triggers
  • OpportunityTeamMember is backend name of Sales Team
  • For creation of Account Team we need to create Account Share which will bethere at the backend
  • For creation of Sales team, we need to create Opportunity Share which will be there at the backend
Note: For more clarity, go to the Data Loader and click on the “Export” operation and click on the select “Show all Salesforce Objects” checkbox, then we can able to see Account Share and Opportunity Share.

Lightning Inter-Component Communication Patterns

Lightning Inter-Component Communication Patterns If you’re comfortable with how a Lightning Component works and want to build producti...