3

One of our objects has about 50 checkboxes. I've been asked to create a picklist that allows a user to "Check All" or "Uncheck All" of the checkboxes. My first thought was a workflow rule, but creating 100 field updates, and two rules based on the picklist seemed excessive. I assume a trigger would work better, but I'm having issues with the logic.

trigger UpdateAllCheckboxesOnOSR on Issue__c (before insert, before update) {


for (Issue__c issueNew : Trigger.new){
    Issue__c issueOld = Trigger.oldMap.get(issueNew.ID);

    if(issueOld.Official_Statement_Checklist__c != issueNew.Official_Statement_Checklist__c){

        if(issueNew.Official_Statement_Checklist__c == 'Check All'){
            issueNew.Principal_Amount_Sources_of_Payment__c = True;
        }
        if(issueNew.Official_Statement_Checklist__c == 'Uncheck All'){
            issueNew.Principal_Amount_Sources_of_Payment__c = False;
        }

    }
}

}

If I can get this to work, I'll add all of the other fields for update to True or false. But wanted to get feedback from the community if a trigger is the best way to do this? And if so, why is my trigger not firing as I expected.

6
  • 1
    is this a standard page or a vf page?
    – PepeFloyd
    Jun 9, 2015 at 21:52
  • 1
    @adrianLarson has a good solution, but you should also think about clearing the `Official_Statement_Checklist' field before exiting the trigger in case user wants to selectively check/uncheck in a subsequent transaction
    – cropredy
    Jun 9, 2015 at 22:05
  • 1
    I see issues all over in this trigger, how did this trigger even save ? you have used issue.Principal_Amount_Sources_of_Payment__c , I do not see issue declared anywhere in your code, you are using single = in your If loop.
    – Rao
    Jun 9, 2015 at 22:25
  • Apologies, I retyped the trigger from one PC to another (long story) and clearly botched a bunch of it. I've made a couple additional changes. In short tho, if the picklist changes from any state to "Check" or "Uncheck" then all of the listed checkboxes would get updated.
    – HomerJ
    Jun 9, 2015 at 22:31
  • So you actually have two checkboxes, correct? That's the only thing that made sense to me. In which case, they should both evaluate to true or false in your trigger and can be reset in a before trigger to false without any recursion as I've shown in my answer. I wasn't quite certain what you were doing to get the values you had.
    – crmprogdev
    Jun 9, 2015 at 22:36

3 Answers 3

4

Question : Is trigger the best approach?

Answer: not as per my humble opinion after process builder was introduced with update records feature

Process builder has its limitations, but in your case I think this would be the best route.

https://help.salesforce.com/apex/HTViewHelpDoc?id=process_considerations.htm&language=en_US

Take a look at process builder, I would go process builder route since you do not have to custom code.

Create a process that has criteria as picklist = "Check All" and add 50 checkbox fields = true

For false add criteria picklist = "Uncheck All" and add the same 50 rows and set checkbox = false

( I do not see a limit on number of rows ( object variables ) you can set on the process as such)

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

https://help.salesforce.com/HTViewHelpDoc?id=process_overview.htm

The available value types are:

Currency—manually enter a currency value.

Boolean—choose a true/false boolean value.

DateTime or Date—manually enter a date/time or date value.

Formula—create a formula expression.

Global Constant—choose a global constant to set a value to null or an empty string—for example, choose $GlobalConstant.Null.

ID—manually enter a Salesforce ID value, for example, 00300000003T2PGAA0.

MultiPicklist—choose one or more multi-select picklist values.

Number—manually enter a number value.

Picklist—choose a picklist value.

Reference—choose a field on the record or on a related record.

String—manually enter a string value.

enter image description here

6
  • I agree it is preferable in a lot of ways, but it could be incredibly tedious to maintain at the same time.
    – Adrian Larson
    Jun 9, 2015 at 22:25
  • @AdrianLarson Major advantage of this to me is flexibility, I can activate and deactivate the process builder any day any time unlike triggers and classes.
    – Rao
    Jun 9, 2015 at 22:28
  • 1
    Indeed, if you trust your admin to have time to manage that process and to not make any mistakes. Not all of us have that luxury.
    – Adrian Larson
    Jun 9, 2015 at 22:31
  • I love this idea, simply because it gives me a chance to start using Process Builder. I'm going to give this a shot and "answer" if I can get it to work. Thanks @rao
    – HomerJ
    Jun 9, 2015 at 22:48
  • 1
    It is working PERFECTLY! There is quite a bit of setup, but configuring on the fly with the UI is still better than code and test coverage. Process Builder is my new best friend (sorry Mike).
    – HomerJ
    Jun 10, 2015 at 14:04
5

I am not sure how to interpret your trigger, but here is how I would find all Checkbox fields in Execute Anonymous:

Set<Schema.SObjectField> checkboxFields = new Set<Schema.SObjectField>();
Schema.DescribeSObjectResult describe = Issue__c.sObjectType.getDescribe();
for (Schema.SObjectField field : describe.fields.getMap().values())
{
    // you may want to cache the below describe and also check isCustom, etc.
    if (field.getDescribe().getSOAPType() == Schema.SoapType.BOOLEAN)
    {
        checkboxFields.add(field);
    }
}

Then setting all these fields to either true or false is fairly straightforward.

for (Schema.SObjectField field : checkboxFields)
{
    issue.put(field, true);
}

This is one of the few instances where I think a blacklist might be helpful. You could use a Field Set to exempt fields you don't want this to apply to:

public static Set<String> exemptCheckboxes
{
    get
    { // optional lazy loading pattern
        if (exemptCheckboxes == null)
        {
            exemptCheckboxes = new Set<String>();
            Schema.FieldSet blacklist = SObjectType.Issue__c.FieldSets.Blacklist;
            for (Schema.FieldSetMember field : fieldSet.getFields())
            {
                exemptCheckboxes.add(field.getFieldPath());
            }
        }
        return exemptCheckboxes;
    }
    private set;
}

Then the if condition inside of your for loop would change like so:

Schema.DescribeFieldResult fieldDescribe = field.getDescribe();
if (!exemptCheckboxes.contains(fieldDescribe.getName().toLowerCase() &&
    fieldDescribe.getSOAPType() == Schema.SoapType.BOOLEAN)
2
  • I like the idea, but there are other checkboxes on the object unrelated to this update, so I can't mark "all" of them with the trigger. But thank you (I learned something new already).
    – HomerJ
    Jun 9, 2015 at 22:29
  • 1
    @HomerJ I added how I would approach that issue. I do think in general Process Builder is the more "correct" approach here, but will also require more maintenance.
    – Adrian Larson
    Jun 9, 2015 at 22:46
2

This is a BEFORE trigger. You want to change the values that are held in Trigger.new, not Trigger.old.

You don't need to compare it to the previous value from Trigger.old as it doesn't matter. If it's checked (true), you update the picklist values for those IDs in Trigger.new or the new records that are about to be inserted which don't have Ids.

Edit

Since you have checkboxes, they should probably be reset at the end of your trigger. This can sometimes create issues with recursion, but shouldn't in your case since you have a before trigger. Your logic should look something like this:

For(Issue__c I:Trigger.new){

   If(I.Official_Statement_Checklist_A__c == True || I.Official_Statement_Checklist_U__c == True){
    // This line catches and filters all records that need to have their checkboxes set or reset

      If(I.Official_Statement_Checklist_A__c == True){
         I.Principal_Amount_Sources_of_Payment__c = True;
         // add your other lines for values to set to true
         I.Official_Statement_Checklist_A__c = False;
         // above line should reset checkbox value to False
      }

      If(I.Official_Statement_Checklist_U__c == True){
         I.Principal_Amount_Sources_of_Payment__c = False;
         // add your other lines for values to set to false
         I.Official_Statement_Checklist_U__c = False;
         // above line should reset checkbox value to False
      }
   }
}

I'd also recommend implementing @AdrianLarson schema calls to get your fields. That will save a lot of hard coding.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .