Let’s look at our old example where we used Trigger.old and got a list of IDs for values that changed:

trigger FirstName on Contact(after update){
    FirstNameHelper.replaceName(trigger.old);
}
public class FirstNameHelper{

    public static void replaceName(List<Contact> con){
        List<ID> conId = new List<ID>();
        List<Contact> finalList = new List<Contact>();

        for (Contact iterator: con){
            if(iterator.FirstName == 'John'){
                conId.add(iterator.Id);
            }
        }

        List<Contact> updateList = [SELECT ID, FirstName FROM Contact WHERE ID = :conId];

        for (Contact iterator: updateList){
            iterator.FirstName = 'Smith';
            finalList.add(iterator);
        }

        update finalList;
    }
}

To quickly sum this up, we first got values from Trigger.old, ran a for loop to see for values where the name was John, got their ID, ran a SOQL query to get values and then a for loop to update the name. This piece of code cam be simplified using Trigger.oldMap which returns a list of IDs of old version of records.

trigger FirstName on Contact (before update){
    FirstNameHelper.repalceName(trigger.oldMap, trigger.new);
}
public class FirstNameHelper{

    public static void replaceName(Map<ID, Contact> oldCon, List<Contact> newCon){

        for (Contact iterator: newCon){
            Contact oldLastName = oldCon.get(iterator.id);

            if (oldLastName.firstName.equals('John')){
                iterator.firstName = 'Smith';
            }
        }

    }
}

Let’s break this code down:

FirstName Trigger

  • We run a before update trigger instead of after update
  • We pass two input parameters this time, trigger.oldMap and trigger.new

FirstNameHelper Class

  • Our method replaceName now takes two in parameters, a Map<ID, Contact> and a List<Contact>.
    • A trigger.oldMap or trigger.newMap will always return a Map of IDs and sObject type.
    • A trigger.new or trigger.old will return List of sObject type.
  • We make a new for loop that runs over the trigger.new values
  • We make a new variable called oldLastName and assign it the ID of values from the trigger.new value
    • We are going through values that have been updated and searching for the same ID in our old values. If there’s a match, we assign the value to a new variable.
  • Now we check if the old value for FirstName was John.
  • If it was John, we assign it the value Smith instead.

To simplify it further, we have two lists, one labelled new and the other labelled old. Assuming we don’t know what values are there in the list, we first pick up the new list and see if the same value exists in the old list. If it does exist, we then check for it’s values. If the previous value was John, we update the value in our new list to Smith.

A quick real life scenario would be while working with Opportunities, we want to assign a new task to the Opportunity owner if the value changes from ‘Needs Analysis’ to ‘Value Proposition’. We check for the old value of the opportunity using Trigger.oldMap and compare it with Trigger.new value and if they are true, we create a new task and assign it to the Opportunity. Go ahead and try it yourself to see if you really understood the concept. Incase you get stuck or need the answer, here’s my code:

Trigger File

trigger oppUpdate on Opportunity(before update){
    oppUpdateHelper.assignTasker(Trigger.oldMap, Trigger.new);
}

Trigger Class Helper File

public class oppUpdateHelper {

    public static void assignTasker(Map<ID, Opportunity> oldList, List<Opportunity> newList){

        for(Opportunity iterator: newList){

            Opportunity oldOpp = oldList.get(iterator.id);

            Boolean oldValue = oldOpp.stageName.equals('Needs Analysis');
            Boolean newValue = iterator.StageName.equals('Value Proposition');

            if(oldValue && newValue){
                Task newTask = new Task();
                newTask.Subject = 'Call regarding ' + iterator.Name + ' opportunity';
                newTask.WhatId = iterator.id;
                newTask.Priority = 'Normal';
                newTask.Status = 'Not Started';
                newTask.Description = 'Made using Apex Trigger';
                insert newTask;
            }

        }

    }

}

Quick breakdown:

  • We make 2 boolean variables that check for values.
  • We run an if statement and the AND operator to check if both values are true.
  • We create a new task, assign the owner of this task to the opportunity and insert it.

Common errors:

  • A Task needs the Subject field to be added. A common error made by new developers is to omit necessary fields. To get a clearer view on this, make a new Task in your org without code and see what fields are necessary
  • The WhatID field of a Task is used to assign tasks.

Summary

  • Trigger.oldMap and Trigger.newMap return a Map of ID and sObjects
Day 13: Week 2 Test