Salesforce coding lessons for the 99%
Finally, Apex tutorials for point-and-click admins! Written by a self-taught Google engineer.
  • Beginner Tutorials
    • Apex
    • Certifications
    • Career Info
    • Technical Architect
    • Visualforce
    • Videos
  • Apex Academy
  • Success Stories
  • About Me
  • Misc
    • Mailbag
    • Challenges
    • Links
    • Login to my Org
Follow @dvdkliuor SUBSCRIBE!

When to use “before” vs “after” triggers

January 25, 2014

Preface: this post is part of the Advanced Apex Concepts series.

Let me give you the definitive answer to perhaps the most commonly asked Apex question:
“Should I use a before or after trigger?”

95% of triggers are before triggers – so if you’re unsure, go with before!

You may be wondering why so many triggers are before triggers. There’s a good reason – they’re simpler to use. If you need to make any changes to a record entering your after trigger, you have to do a DML statement. This isn’t necessary in a before trigger – changes to records entering your trigger always save!

The specific use case of an after trigger is when you need to associate any record to a record being created in your trigger. Here’s an example:

// Automatically create an Opp when an Account is created
trigger AutoOpp on Account(after insert) {
List<Opportunity> newOpps = new List<Opportunity>(); for (Account acc : Trigger.new) { Opportunity opp = new Opportunity(); opp.Name = acc.Name + ' Opportunity'; opp.StageName = 'Prospecting'; opp.CloseDate = Date.today() + 90;
opp.AccountId = acc.Id; // Use the trigger record's ID
newOpps.add(opp); } insert newOpps; }

Moral of the story – before triggers are kings of the jungle! You could say they are “apex” predators in Salesforce, ha ha ha..

Next post: Debug your code with System.debug!

75 Comments
Ashish Burnwal
August 9, 2021 @ 2:44 am

Hi David,
I’m following your Apex Academy: Absolute Beginner’s Guide to Coding in Salesforce an there you taught about HelloWorld Trigger where we are using after update but why it is invoked while creating a record (Cuz before Insert is needed for it) . So why after update is being invoked when I create a record.(I’ve used a freshly created playground for it ).
Thank You

Reply
Aryan jha
September 14, 2020 @ 10:35 pm

Sir I have a query in which case we need to use after insert and after update trigger.This is confusing when to use after Insert and after update trigger.Can u help me to figure it out

Reply
Andrew B
November 8, 2019 @ 11:52 am

When I set an Opportunity to complete and that same opportunity meets certain conditions, I need to create a clone of that opportunity with a different opportunity record type. Before or After trigger? Or both?

Reply
    David Liu
    November 8, 2019 @ 12:01 pm

    Try before first!

    Reply
Krishna Bidwai
March 20, 2019 @ 3:03 am

Hi David,

If there is field update on the other records related to the record being updated then in this case it should be before or after ?

Best Regards,
Krishna Bidwai

Reply
    Ankit Chowhan
    September 1, 2019 @ 11:48 pm

    After Trigger

    Reply
Prem Chauhan
May 3, 2018 @ 10:39 pm

Hi David Liu,

Thanks for giving the clear picture of When to use before vs after triggers.
My doubt has vanished now. Finally, I am able to write Apex Trigger.

Thanks for sharing this article.

Reply
    David Liu
    May 3, 2018 @ 10:42 pm

    Excellent! Congrats!!

    Reply
      sowmya
      September 5, 2018 @ 8:34 am

      Hi david,

      I have a requirement,can you please help me how to resolve the task,can it be resolved by using the trigger or can we use the process builder? Here is my requirement below

      Assume that i have Amount field on Account and as well as on Contact.if i change the amount on account,all the child should update with the equal amount and all the total amount should be equal to account amount.
      for ex:if account(amount_field)=100,i have 10 childs contacts for account,each child contact should have amount_field value as 10 so total should be equal to account(amount_field).
      each child

      Reply
        Mahi
        June 13, 2019 @ 4:08 pm

        trigger splitTotalAmount on Account (after update) {

        Map myMap = trigger.newmap;

        List lstc = [select id,name,accountid,Amount__c from contact where accountId in:mymap.keyset()];
        List cc = new List();
        for(contact c:lstc){
        c.Amount__c = myMap.get(c.AccountId).Total_Amount__c/lstc.size();
        cc.add(c);
        }
        update cc;

        }

        Reply
          Ankit
          December 13, 2020 @ 10:43 am

          Great!

          Reply
Dilip Kulkarni
April 20, 2017 @ 3:06 am

Hi David,
I wrote trigger as following:

trigger UpdateSADeclined on Task (before insert,before update) {

for(Task x: Trigger.new)
{
If (x.Declined_by__c==null|| x.Date_Time_Declined__c==null|| x.Declined_Reason__c==null)
{

x.SA_Declined__c=true;
}
else
{ x.SA_Declined__c=false;

}
}
}

By this trigger checkbox field SADeclined is checked whenever any of date field value ( declined by, date time declined and declined reason) is null, otherwise it’s unchecked ( means whenever all three fields are populated).

Now, My requirement is whenever there is value in date field SADeclined should be unchecked, i.e. when all three date fields are null the SADeclined will be checked.

Kindly help me solve this.

Reply
    Nish
    July 11, 2018 @ 10:26 pm

    Change 1 line of your code to this :
    If (x.Declined_by__c==null && x.Date_Time_Declined__c==null && x.Declined_Reason__c==null)

    Basically replace OR operator with AND.

    Reply
Dilip Kulkarni
March 14, 2017 @ 7:13 am

Hi David,
I am working in SFDC. I have two certs. ( ADM201 and platform app builder). As I am mechanical engg., I have little coding knowledge. sfdc99 is really helping me to learn the basic coding. Great work!!!

Reply
    David Liu
    March 14, 2017 @ 10:36 pm

    Thank you Dilip!

    Reply
      Arun
      April 27, 2018 @ 7:44 pm

      Hi David,

      To introduce my self I am Arun. Your website SFDC99 is really superb. All of your articles are great articles and inspiring many people like me.

      I have a question regarding triggers. I am going through Apex Design patterns “Bulk State Transition” pattern which is related to triggers. In the example given why the trigger is after trigger(“after insert, after update) instead before trigger. I do not see any ID that is being used in the example given. Can you please clarify..? Would appreciate your help.

      here is the link for your reference https://developer.salesforce.com/page/Apex_Design_Patterns
      Please look for the last pattern

      Thanks
      Arun

      Reply
        David Liu
        April 30, 2018 @ 9:41 pm

        Thanks Arun!

        The code in line 17 very likely will use the opp ID, since it needs to associate the order with the opp!

        17: new OrderClass().CreateOrderFromOpptys(closedOpptyList);

        Cheers =)
        David

        Reply
          Anonymous
          May 1, 2018 @ 5:04 pm

          Got it. Thank you for the clarification !!

          Reply
Dnyaneshwar Kendre
December 4, 2016 @ 9:27 pm

Hi David,

I am trying to check if Lead to insert is duplicate and if it is then store it in separate custom object(Duplicate_Lead__c). but in query it is returning the record i am inserting i.e. for every lead i insert this trigger is matching its fields with itself and creating duplicate record in custom object.

How to avoid this?

trigger LeadDuplicateTrigger on Lead(after insert) {

List Exleads = [Select id, name, email, MobilePhone, Program__c From Lead];
List DupLeads = new List ();

for(Lead l : Trigger.new){
for(Lead Ele : Exleads){

if(( (l.email == Ele.email) && (l.Program__c==Ele.Program__c) ) || ( (l.MobilePhone == ELe.MobilePhone) && (l.Program__c==Ele.Program__c) )){
Duplicate_Lead__c DPLead = new Duplicate_Lead__c();

DPLead.Name = ‘Duplicate Of’+’ ‘+ Ele.Name;
DPLead.Admission_Stage__c = l.Admission_Stage__c;
DPLead.Admission_Status__c = l.Admission_Status__c;
DPLead.Agency__c = l.Agency__c;
DPLead.Initial_Owner__c = l.Initial_Owner__c;
DPLead.Initial_program__c = l.Initial_program__c;
DPLead.Program__c = l.Program__c;
DPLead.Lead_State__c = l.Lead_State__c;
DPLead.Test_Score__c = l.Test_Score__c;

DupLeads.add(DPLead);

}

}

}

Insert DupLeads;

Reply
    Dnyaneshwar Kendre
    December 4, 2016 @ 11:47 pm

    Hi,

    I have managed to get required output. But just want to check is there anything i am doing wrong..Any other better way of achieving the same:

    [ Requirement : there is a Lead record 1 (email=abc@gmail & program__c=ABC) exist in system….then i insert Lead record 2 (email=abc@gmail & program=ABC) now field values of Lead record 2 are copied in custom object (Duplicate_Lead__c) and then remove record 2. ]

    trigger LeadDuplicateTrigger on Lead(after insert) {

    List Exleads = [Select id, name, email, MobilePhone, Program__c From Lead WHERE Id NOT IN : Trigger.new ];
    List DupLeads = new List ();

    for(Lead l : Trigger.new){
    for(Lead Ele : Exleads){

    if(( (l.email == Ele.email) && (l.Program__c==Ele.Program__c) ) || ( (l.MobilePhone == ELe.MobilePhone) && (l.Program__c==Ele.Program__c) )){
    Duplicate_Lead__c DPLead = new Duplicate_Lead__c();

    DPLead.Name = ‘Duplicate Of’+’ ‘+ Ele.Name;
    DPLead.Admission_Stage__c = l.Admission_Stage__c;
    DPLead.Admission_Status__c = l.Admission_Status__c;
    DPLead.Agency__c = l.Agency__c;
    DPLead.Initial_Owner__c = l.Initial_Owner__c;
    DPLead.Initial_program__c = l.Initial_program__c;
    DPLead.Program__c = l.Program__c;
    DPLead.Lead_State__c = l.Lead_State__c;
    DPLead.Test_Score__c = l.Test_Score__c;

    Lead updLead=[select id from Lead where id = :Ele.id];
    updLead.Duplicacy__c = true;
    Update updLead;

    Lead DelLead=[select id from Lead where id = :l.id];
    Delete DelLead;

    DupLeads.add(DPLead);

    }

    }

    }

    Insert DupLeads;
    }

    Reply
Wayne Solomon
September 14, 2016 @ 2:37 am

I read so much documentation on this and laughed so hard after looking at the graphic which is absolutely accurate and simple to understand. Before seeing this I was getting “Read-only” errors and so forth. Thanks so much!

Reply
Jijaji
August 9, 2016 @ 10:53 pm

bro the joke was very bad.need to improve humor skills.

Reply
    David Liu
    August 10, 2016 @ 3:25 pm

    LOL!

    Reply
monsieur
July 1, 2016 @ 9:57 am

This graphic is COMPLETELY WRONG.

Salesforce’s own documentation on Triggers (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers.htm) states:

“There are two types of triggers:

– Before triggers are used to update or validate record values before they’re saved to the database.
– After triggers are used to access field values that are set by the system (such as a record’s Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.”

Reply
    David Liu
    July 1, 2016 @ 5:05 pm

    Salesforce and I agree Monsieur =)

    The graphic is just a simplification of the text from the Salesforce documentation, which is a very confusing read!

    David

    Reply
Dani Reddy
December 13, 2015 @ 5:53 am

Thanq Good Code

Reply
Sinan
August 18, 2015 @ 10:41 am

Hi David,

I have written your trigger in the below form – I am trying to bulkify the code! would that be correct too in this instance?

// Create an opp when an Account is created
trigger CreateOppWhenAccountCreated on Account (after insert) {

List newOpportunities = new List();

for (Account account : trigger.new) {
Opportunity opp = new Opportunity(Name=account.Name + ‘ opportunity’,
StageName=’Prospect’, CloseDate=Date.today() + 90,
AccountId=account.Id);
newOpportunities.add(opp);
}

insert newOpportunities;

} // end trigger

Thank you, Sinan

Reply
    David Liu
    August 18, 2015 @ 7:07 pm

    You got it, great job Sinan!!

    Reply
rushi
June 19, 2015 @ 8:13 pm

Hi David, first of all thank you so much.I got my DEV 401 and ADM201, just started apex programming and your lessons are so helpful.Now i am working on triggers and my question is “why can’t we create triggers in setup at Develop/apex triggers(because we don’t have new button, so we have to use developer console to create triggers)”

Reply
    Andrea Ianni
    July 3, 2015 @ 6:12 am

    You’re right! For the Apex Class you can…. for the Triggers you cannot! I think it’s a choice of Salesforce. Maybe because they think the Triggers could be more harmful!

    Reply
    Anonymous
    August 22, 2015 @ 9:06 am

    Hey rushi, you can create triggers from Setup, not from Develop>Apex Triggers but from the Object itself. For standard objects (like Account), Account>Triggers>New. For Custom Objects, Custom Object>Triggers>New.

    Reply
Saikishore
May 30, 2015 @ 7:59 am

Great site David….It realy helps us..

Reply
AR
April 21, 2015 @ 3:19 am

Hi David,

Thanks for the Post.

I have understood the post shared by you, but I am still not confident accepting it while considering the concept of Apex Transaction Roll Back. Please share your thoughts on it.

Consider the scenario where I need to create object B on update of object A. Typically, I should create a ‘before update’ Trigger that calls a class which creates a record in object B.

Per the ‘Apex Transaction’ concept, if there is a failure outside the transaction boundary like due to Custom Validation Rules (that executes after Before Triggers and before Record Save), a roll back will not happen. Because in this scenario the transaction boundary will be the Trigger (including any class that it invokes).

This would lead to inconsistency in the system – Object B record created while Object A record still not saved with the updates.

Am I getting all this correctly?

Thanks for your help,
AR

Reply
    manoj
    May 22, 2015 @ 11:30 am

    If you want to create a record in object b after updating a record in object a, then you should use AFTER update trigger and not BEFORE trigger.

    Reply
Santhi
March 4, 2015 @ 9:24 pm

Hi David,

Good session from you. Below is my understanding out of ur session.

1. Before trigger, if at all the triggered records had to follow some complex business rules / go with some modifications before it can be saved. Its a before save scenario.

2. After trigger, means a record is already saved to DB, what next? insert / update dependent objects, fire future calls (may be for some webservice calls / api for sync up with different systems etc) and so on.

Thanks,
Santhi C

Reply
    David Liu
    March 7, 2015 @ 12:57 am

    Yes you’re getting the hang of this!

    Reply
    Arpit
    April 9, 2015 @ 9:48 am

    I got more understanding by your explanation. Thanks :)

    Reply
Deepthi Reddy
March 3, 2015 @ 3:13 am

HELP me through this . Task is to implement a trigger on contact This trigger should check that

1.related account must not have more than 10 childs.
2.Update child count in account through trigger whenever a contact is created or update or deleted.
3.While creating a new record in contact it should not allow duplicate record which have email and mobilenumber.

Reply
Ram
December 22, 2014 @ 2:45 am

Hi david you are doing good job keep it up!!!

Reply
MUNI
October 11, 2014 @ 11:48 pm

trigger AutoOpp on Account(after insert) {
List newOpps = new List();
for (Account acc : Trigger.new) {
Opportunity opp = new Opportunity();
opp.Name = acc.Name + ‘ Opportunity’;
opp.StageName = ‘Prospecting’;
opp.CloseDate = Date.today() + 90;
opp.AccountId = acc.Id; // Use the trigger record’s ID
newOpps.add(opp);
}
insert newOpps;
}

am getting error like Loop variable must be Sobject type

Reply
    chitral
    October 13, 2014 @ 12:26 am

    @muni
    its working fine
    just copy paste this code.

    trigger AutoOpp on Account(after insert)
    {
    list newOpp = new list();
    for(Account acc: trigger.new)
    {
    opportunity opp = new opportunity();
    opp.Name = acc.Name + ‘ Opportunity’;
    opp.StageName = ‘Prospecting’;
    opp.CloseDate = Date.today() + 90;
    opp.AccountId = acc.Id; // Use the trigger record’s ID
    newOpp.add(opp);
    }

    insert newOpp;
    }

    Check in your code
    opp.Name = acc.Name + ‘ Opportunity’; ( opportunity should be single quote ‘opportunity’).
    opp.StageName = ‘Prospecting’; (same here).

    Reply
    Sunil Nangare
    November 4, 2014 @ 11:44 am

    Add this code line for list declaration.
    List newOpps = new List();

    Reply
      Sunil Nangare
      November 4, 2014 @ 11:46 am

      List newOpps = new List();

      Reply
      Anonymous
      August 1, 2015 @ 5:09 am

      list new_opp = new list();

      Reply
    Mang Kanor
    November 19, 2014 @ 10:36 pm

    try defining the object that your List should be holding e.g.
    List newOpps = new List();

    Reply
    Anonymous
    December 28, 2014 @ 5:22 am

    Hello sir…
    You are declareda as “list” fine but what type of list that is? So declare ad
    List newpp= new list.

    Reply
      David Liu
      December 28, 2014 @ 6:36 pm

      Not sure what the question is sorry! Can you provide more detail?

      Reply
    prabir rath
    February 17, 2015 @ 10:47 pm

    Hi,

    Your error in Line#2. replace it to List newOpps = new List();

    Enjoy (Y)

    Reply
    Mohd asim uddin
    December 1, 2015 @ 1:20 am

    after line1 u should write
    if(Trigger.isInsert){

    Reply
shridevi
September 25, 2014 @ 9:01 pm

Hi David,
I am new to Apex programming. I wrote one trigger. I dont know whether it is right or wrong pls guide me. my code is below

Problem:

1) when an account is set to active, the address on the account should be copied as a primary address on the related list
2) if there is a duplicate, dont insert new address, but make the existing one primary
3) if user changes the address on the account screen, insert a new address on the related list and make this new as a primary (dont delete the old primary address)

I have 3 things to do in one trigger.

Code:

trigger updateprimaryaddress on Account (after update,after insert) {
// list updateToaddress = new list();
list changedAccount = new list();
setids = Trigger.newMap.keyset();
if(trigger.isupdate){
for(Account a : trigger.new){
if(a.status__c == ‘Active’) {

list newacctsaddr = new list();
newacctsaddr = [select id, address__c,city__c,country__c from account where id in :trigger.New];
if(a.address__c != trigger.oldMap.get(a.id).address__c||
a.city__c != trigger.oldMap.get(a.id).city__c||
a.country__c != trigger.oldMap.get(a.id).country__c) {
newacctsaddr.add(a);
}
} else if(trigger.isInsert){
list updateToaddress = new list();
updateToaddress = [select account__c,address__c,name__c,city__c,country__c from address__c where id in :ids];

for(address__c ad : updateToaddress) {
ad.name = a.country__c;
ad.account__c = a.name;
ad.address__c = a.address__c;
ad.city__c = a.city__c;
ad.country__c = a.country__c;
ad.primary_address__c= True;
ad.IFS_linked__c = True;

updateToaddress.add(ad);
}

if(!updateToaddress.isEmpty()){
update updateToaddress;

}
}
}
}
}

But it is not working for me. If i create one account with address information when status is made active, it is going to address related list.
pls help.

Reply
chitral
September 16, 2014 @ 12:44 pm

hi david ,
m stuck here

in this vf page the quick access menu display arrow button initialyy, (when we click the arrow button the quick acces menu opens) similar to salesforce quick acces menu …
i want that instead of arrow it shud be wriiten FAQ (vertically) like this

F
A
Q

aroow button may/maynot be present but i require that FAQ to display .

//code

//arrow button ..here how do i add FAQ vertically

//code

Reply
    chitral
    September 16, 2014 @ 12:46 pm

    i cudnt post my code here

    Reply
kaveri
July 13, 2014 @ 6:08 pm

Hi David
I came across these words Recursive Trigger and Circular Triggers ….. Can u explain me those things and where do we use them

Reply
    David Liu
    July 15, 2014 @ 10:13 pm

    This is recursion!

    Pretty rare that you’ll ever need to use it!

    Reply
Sahiti
June 17, 2014 @ 6:37 pm

Excellent site really an thankful to you

Reply
Viru
June 11, 2014 @ 3:38 am

Hey David !
First of all thanks, you are doing such a great job !

after this post i know which time i have to use after trigger and which time i have to use before trigger but only the time when i create a record i mean at ” insert ” time.

I am confused for the Update event. I mean in inserting time i know if i need record id then i have to use after trigger but in update, (i think ) we have record id in both event before and after so what we have to use?

Reply
    David Liu
    June 11, 2014 @ 5:15 pm

    Great question!

    A lot of triggers are after insert, before update. Both don’t have to be insert and I recommend using after insert, before update as well!

    Reply
Jagadeesh Naidu
June 6, 2014 @ 11:34 pm

Hi guys Nice Explanation..

Thanks for your valuable discussions.

Reply
santosh
May 13, 2014 @ 12:06 am

trigger AutoOpp on Account(after insert) { List newOpps = new List();
for (Account acc : Trigger.new) {
Opportunity opp = new Opportunity();
opp.Name = acc.Name + ‘ Opportunity’;
opp.StageName = ‘Prospecting’;
opp.CloseDate = Date.today() + 90; opp.AccountId = acc.Id; // Use the trigger record’s ID newOpps.add(opp);
}
insert newOpps;
}

Error: Compile Error: Variable does not exist: Name at line 4 column 23

I m getting this why i m getting this error.?
please give me some examples to write the effective trigger

Reply
    David Liu
    May 17, 2014 @ 10:51 am

    Saves 100% in my org!

    Reply
      Moin
      May 27, 2014 @ 6:10 am

      Add ListnewOpps=new List(); before the for loop

      Reply
    sasidhar
    May 31, 2015 @ 10:45 am

    hi santosh,

    opp.Name = acc.Name + ‘ Opportunity’;//reason is single code problem in ‘opportunity’

    don’t copy this line particularly in your trigger page..just type and execute you got a solution

    ALL THE BEST

    thanks
    sasidhar

    Reply
Amit
March 28, 2014 @ 3:31 am

Hi David,

First of all a BIG THANK YOU. Your efforts for making this site is clearing my many and more concepts and improvising my coding style for writing more efficient, scalable code. First time, I am feeling like I am learning code. THANK YOU VERY MUCH.

I have some below questions on this topic:

1) In the above diagram, in one of decision box, you have stated ‘Does the trigger run on insert’. Here, ‘Insert’ means on click of ‘Save’ button/Insert of records through tools like Data Loader etc? Am I considering it correct?

2) Why we need to use DML Statement in ‘after trigger’ and not in ‘before trigger’?

3) First reason of using after trigger is ‘when you need to associate any record to a record being created in your trigger’.
Can you explain some more scenarios(from your daily coding experience) where we should use ‘after trigger’ ?

Thank you,
Amit

Reply
    David Liu
    March 28, 2014 @ 5:04 am

    wOOt wOOt!

    “on insert” means any time a record is created, whether it’s created through Data Loader or a Save button!

    DML is needed in after triggers because after insert/update literally means “after the DML happens”. So before insert/update means “before the DML happens”. The DML I’m referring to is the implicit DML happening when you hit the “Save” button!

    After triggers are only needed when you need the ID of the records being created. Most of the time you’ll need these IDs only if you’re relating completely new or different records to it in a Lookup or Master-Detail field. For example, if I want to relate Task X to every new Contact being created, I’d need the Contact ID to populate in a Task field.

    Hope this helps! Check out the quiz for that Chapter for more examples!
    David

    Reply
      Carrie
      May 30, 2014 @ 2:18 pm

      I had a use case today where an after trigger was required. I was updating related child records when certain fields on the parent were updated. Regular text fields were updated on the child record no problem, but the picklist fields were acting funny. Once I changed the trigger to an after trigger, the picklist fields were updated correctly.

      Reply
        David Liu
        May 31, 2014 @ 9:43 am

        Great use case! There actually are rare cases where the diagram above is too simple to make this call! I will talk about this in a future post!

        Reply
Ian
March 12, 2014 @ 3:27 pm

David,

I’m struggling with a trigger. I was thinking about whether doing an after insert would help but I think the issue is in the test class, rather than the trigger.

Here’s the scenario: when creating an event of type “New Member Briefing” I want the custom date field “Member Announcement Date” on the client’s contact record to be copied into the same field on the event record so I can do a report on the number of days between “new member announcement” and the date of the event (I have a UsableDueDate field and trigger set up to allow me to do this).

Below is my trigger so far. It’s based on somewhat a similar scenario I found online. I may have got confused because in the example I cribbed from the date field was going from child to parent not parent to child. It’s my first one, so please bear with me.

trigger NMBDateTrigger on Event (after insert) {

List EventIDs = new List();
List updateNmbEvents = new List();
for (Event nmbEvent : trigger.new) {
EventIDs.add(nmbEvent.Id);
}
Map ContactUpdateMap = new Map();
for (Contact newmember : [Select ID, member_announcement_date__c FROM Contact WHERE ID in:EventIDs])
{
ContactUpdateMap.put(newmember.ID, newmember);
}
for (Event nmbEvent : trigger.new) {
Contact updateNmbEvent = ContactUpdateMap.get(nmbEvent.Id);
if (nmbEvent != null) {
if (nmbEvent.Type == ‘New Member Briefing’) {
updateNmbEvent.Member_Announcement_Date__c = nmbEvent.Member_Announcement_date__c;
update updateNmbEvents;
}
}
}
}

END OF TRIGGER

Here’s the test class so far.

@isTest
public class TestNMBDateTrigger{
static testMethod void testNmbDate() {
//create records to test
Contact c = new Contact();
c.FirstName =’John’;
c.LastName = ‘Smith’;
c.Member_Announcement_Date__c = System.Today();
insert c;

//create NMB event
Event nmbEvent = new Event();
nmbEvent.Subject = ‘Test NMB Event’;
nmbEvent.Type = ‘New Member Briefing’;

// David, do I need the ID for the contact first?
// If the test contact and event are created at the same time, how do I get this? I wouldn’t expect this to work, as it is.
nmbEvent.WhoId = ‘c.Id’;

try{
insert nmbEvent;
} catch (Exception e) {
System.debug(‘An error happened, as predicted!’);
}
List nmbEvents = [SELECT Id FROM Event WHERE (Member_Announcement_Date__c = TODAY)];
System.assertEquals(1,nmbEvents.size());
}
}

END OF TEST CLASS

I tried to run the code but got an error saying, “System.StringException: Invalid id: c.Id”, which makes sense since the event can’t get the contact ID for the WhoID until after the contact record is created. In real life, this isn’t an issue since the contact is there already but I can’t figure out how to test this. I’m extrapolating from an example test class, so I don’t think it’s finished yet.

Thanks for any help you can provide!

Ian

Reply
    David Liu
    March 12, 2014 @ 8:20 pm

    Hey Ian,

    Better to start this trigger from scratch honestly =) It will be more intuitive and easier to change in the future.

    Here are the steps you need:

    1. Use a before trigger – after triggers are almost never used:
    https://www.sfdc99.com/2014/01/25/use-vs-triggers/

    2. Create a set of all WhoIds on all events
    – Note to only add contacts who IDs, not leads! You can tell by the first three characters of the ID

    3. Do a SOQL query for all Contacts in step 2, making sure the query the contact’s date field:
    https://www.sfdc99.com/2014/01/20/soql-queries-inside-loops/

    4. Add all contacts in step 3 into a Map that points to the date field:
    https://www.sfdc99.com/2014/01/25/use-maps-navigate-across-lists/

    5. For each event, search the map for the right contact ID then populate the date field =)

    Highly recommend doing this process – it’s the template that most triggers follow and will serve you well in the future. Chapter 5 is entirely dedicated to this template =)

    David

    Reply
      Ian
      March 12, 2014 @ 8:28 pm

      Thanks for the guide! I’ll let you know how it goes.

      Reply
upagna
March 3, 2014 @ 9:15 am

..I am following your lessons .great explanations.Thank you for this wonderfull site

Reply
    David Liu
    March 3, 2014 @ 10:35 pm

    Upagna! You have an awesome name!

    Reply
Ravi
January 27, 2014 @ 4:41 am

Great David !
It’s nice to read the best practices with examples at one place. I am waiting your posts on integration with third party api.
Congrats on being MVP.
—–
ravi

Reply
    David Liu
    January 27, 2014 @ 9:09 pm

    Thank you Ravi – integrations will come soon!

    Reply
Mani
January 25, 2014 @ 10:28 pm

No words you really Awesome..I am completely following your lessons what a great explanations..waiting for next lessons..Thank you.. Any ways congrats for MVP..

Reply
    David Liu
    January 25, 2014 @ 10:35 pm

    My pleasure Mani =) Tell your friends!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *


*

*

Theme: Simple Style by Fimply