function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ellsa JamesEllsa James 

How do I edit my trigger to only fire when criteria is met once?

I have written the below trigger which creates a related record when a checkbox is updated. The problem is, it is creating a new record everytime the record is edited since the criteria is being met. Can anyone advise how I can edit my trigger so that it only fires once. (ie.The first time the criteria is met) ?

Trigger
Trigger copyEquipmentonsite on Unit_Placements_Sales__c(after insert, after update)
{
     List<Services__c> sub=new List<Services__c>();
     for(Unit_Placements_Sales__c u : Trigger.new)
     {
           if(u.Service_Month_is_Next_Month__c == TRUE)
           {
                   Services__c s=new Services__c();
                   
                   s.Equipment_Onsite__c=u.ID;
                   s.Equipment_Type__c=u.Equipment__c;
                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c;   
                   s.Product__c=u.The_Product__c;  
                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
                   s.Serial_Number__c=u.Serial_Number__c; 
                   s.XD_Number__c=u.XD_Number__c;
                   
                                                  
                   
                                    
                   sub.add(s);
            }
            if(sub.size()>0)
            insert sub;
     }
}

Thank you
Best Answer chosen by Ellsa James
CheyneCheyne
Actually, your checkbox field would indicate that the trigger has already run (although you could technically do it the other way around, I think it would be more intuitive to have the field indicate that the trigger has already run), so you would want to check that it is false, and if so, perform your trigger actions, and then set that box to true.

Two other things: since trigger.new is read-only, and you are updating the records in trigger.new, you will need to query for these records anew. Also, it would be best to move your DML statements to the outside of the for loop, to avoid hitting governor limits.

Putting it all together, you might have something like this: 

Trigger copyEquipmentonsite on Unit_Placements_Sales__c(after insert, after update)
{
     List<Services__c> sub=new List<Services__c>();
     List<Unit_Placements_Sales__c> unitsToUpdate = new List<Unit_Placements_Sales__c>();
     for(Unit_Placements_Sales__c u : [SELECT Id, Service_Month_is_Next_Month__c, New_Checkbox_Field__c, Equipment__c, Machine_Specific_Notes__c, The_Product__c, Dell_Tag_Number__c, Serial_Number__c, XD_Number__c FROM Unit_Placements__c WHERE Id IN :trigger.newMap.keySet()])
     {
           if(u.Service_Month_is_Next_Month__c == TRUE && u.New_Checkbox_Field__c == false)
           {
                   Services__c s=new Services__c();
                   
                   s.Equipment_Onsite__c=u.ID;
                   s.Equipment_Type__c=u.Equipment__c;
                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c; 
                   s.Product__c=u.The_Product__c;
                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
                   s.Serial_Number__c=u.Serial_Number__c;
                   s.XD_Number__c=u.XD_Number__c;

                   sub.add(s);

                   u.New_Checkbox_Field__c = true;
                   unitsToUpdate.add(u);
            }
            
     }
     
     if(sub.size()>0)
          insert sub;

     if (unitsToUpdate.size() > 0) 
          update unitsToUpdate;
}

All Answers

CheyneCheyne
You need to check the value of that checkbox before the update, by using trigger.oldMap. 

for (Unit_Placements_Sales__c u : Trigger.new) {
    if (u.Service_Month_is_Next_Month__c == true && trigger.oldMap.get(u.Id).Service_Month_is_Next_Month__c == false) {

    }
}

You could also create a checkbox field that this trigger would check on the Unit_Placements_Sales__c object that indicates that the trigger has already run.
Sagar PareekSagar Pareek
Hi Ellsa ,
This might help

Trigger copyEquipmentonsite on Unit_Placements_Sales__c(after insert, before update)
{
     List<Services__c> sub=new List<Services__c>();
     for(Unit_Placements_Sales__c u : Trigger.new)
     {
         if(Trigger.isUpdate){  
		   if(Trigger.oldMap.get(u.Id).Service_Month_is_Next_Month__c!=TRUE && u.Service_Month_is_Next_Month__c == TRUE)
           {
                   Services__c s=new Services__c();
                   
                   s.Equipment_Onsite__c=u.ID;
                   s.Equipment_Type__c=u.Equipment__c;
                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c;   
                   s.Product__c=u.The_Product__c;  
                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
                   s.Serial_Number__c=u.Serial_Number__c; 
                   s.XD_Number__c=u.XD_Number__c;
                   
                                                  
                   
                                    
                   sub.add(s);
            }
		}else
		{
				if(u.Service_Month_is_Next_Month__c == TRUE)
07	           {
08	                   Services__c s=new Services__c();
09	                    
10	                   s.Equipment_Onsite__c=u.ID;
11	                   s.Equipment_Type__c=u.Equipment__c;
12	                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c;  
13	                   s.Product__c=u.The_Product__c; 
14	                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
15	                   s.Serial_Number__c=u.Serial_Number__c;
16	                   s.XD_Number__c=u.XD_Number__c;
17	                    
18	                                                   
19	                    
20	                                     
21	                   sub.add(s);
22	            }
		
		
		
		
		
		
		}
		
		
            if(sub.size()>0)
            insert sub;
     }
}


Ramu_SFDCRamu_SFDC
One way of doing this would be to create a custom checkbox field on the parent object that would set a flag when the child record is created. Next time you would refer to this flag field using if else statement and create or do not create the child record accordingly. Something as the below ('childrecexist'  is the checkbox field in this case)

Trigger copyEquipmentonsite on Unit_Placements_Sales__c(after insert, after update)
{
     List<Services__c> sub=new List<Services__c>();
     for(Unit_Placements_Sales__c u : Trigger.new)
     {
           if(u.Service_Month_is_Next_Month__c == TRUE && U.childrecexist__c==false)
           {
                   Services__c s=new Services__c();
                  
                   s.Equipment_Onsite__c=u.ID;
                   s.Equipment_Type__c=u.Equipment__c;
                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c;  
                   s.Product__c=u.The_Product__c; 
                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
                   s.Serial_Number__c=u.Serial_Number__c;
                   s.XD_Number__c=u.XD_Number__c;
                   sub.add(s);
            }
            if(sub.size()>0){
            insert sub;
            u.childrecexist__c=true;
            update u;

            }
           
     }
}


Thank you
Ellsa JamesEllsa James
Hi @cheyne

Thank you for the quick reply. I like the sound of the second option. Just so I am understanding this correctly- Is the idea to add a line in the trigger that sets this new checkbox to true after the trigger has run and then include this in the trigger criteria.

For example If (u.Service_Month_is_Next_Month__c == true && u.new_checkbox_field__c ==true)
CheyneCheyne
Actually, your checkbox field would indicate that the trigger has already run (although you could technically do it the other way around, I think it would be more intuitive to have the field indicate that the trigger has already run), so you would want to check that it is false, and if so, perform your trigger actions, and then set that box to true.

Two other things: since trigger.new is read-only, and you are updating the records in trigger.new, you will need to query for these records anew. Also, it would be best to move your DML statements to the outside of the for loop, to avoid hitting governor limits.

Putting it all together, you might have something like this: 

Trigger copyEquipmentonsite on Unit_Placements_Sales__c(after insert, after update)
{
     List<Services__c> sub=new List<Services__c>();
     List<Unit_Placements_Sales__c> unitsToUpdate = new List<Unit_Placements_Sales__c>();
     for(Unit_Placements_Sales__c u : [SELECT Id, Service_Month_is_Next_Month__c, New_Checkbox_Field__c, Equipment__c, Machine_Specific_Notes__c, The_Product__c, Dell_Tag_Number__c, Serial_Number__c, XD_Number__c FROM Unit_Placements__c WHERE Id IN :trigger.newMap.keySet()])
     {
           if(u.Service_Month_is_Next_Month__c == TRUE && u.New_Checkbox_Field__c == false)
           {
                   Services__c s=new Services__c();
                   
                   s.Equipment_Onsite__c=u.ID;
                   s.Equipment_Type__c=u.Equipment__c;
                   s.Machine_Specific_Notes__c=u.Machine_Specific_Notes__c; 
                   s.Product__c=u.The_Product__c;
                   s.Dell_Tag_Number__c=u.Dell_Tag_Number__c;
                   s.Serial_Number__c=u.Serial_Number__c;
                   s.XD_Number__c=u.XD_Number__c;

                   sub.add(s);

                   u.New_Checkbox_Field__c = true;
                   unitsToUpdate.add(u);
            }
            
     }
     
     if(sub.size()>0)
          insert sub;

     if (unitsToUpdate.size() > 0) 
          update unitsToUpdate;
}
This was selected as the best answer