1

This is a very frustrating problem because I feel I am using the proper methods but just not getting the results.

I'm trying to sort this picklist I'm creating through Tooling API. I am using the proper 'sorted' setting in the metadata, and the code is indeed setting the 'Display values alphabetically, not in the order entered' checkbox in the picklist to TRUE. But it's not actually sorting the choices until I go in there and press 'Save'.

What am I not doing correctly in this code ? Do I need to be saving again somewhere at the end of this ?

I have updated the code below to try and implement the suggestions given in the thread here. But I am getting errors with my usage. First is the wrapper class. I'm not sure what I'm doing wrong here by renaming Wrapper to PicklistChoiceWrapper. I am getting an error telling me the 'method does not exist' for the return value... line :

Here is the wrapper class....

    public class Wrapper implements Comparable {
    public Map<String, Object> value;
    
    public Wrapper(Map<String, Object> value) {
        this.value = value;
    }
    
    public Integer compareTo(Object o) { // Wrapper
        // Compare 'valueName' instead of 'label'
        return String.valueOf(value.get('valueName')).compareTo(String.valueOf(((Wrapper)o).value.get('valueName')));
    }
}

Here is the main class...

global class PicklistValuesUpdateTestPlayers1 implements Schedulable {
    
    global void execute(SchedulableContext ctx) {
        updatePicklistValues();
    }

    @future(callout=true)
    public static void updatePicklistValues() {
        Date yesterday = System.today().addDays(-1);
        // Query for deactivated users
        List<User> deactivatedUsers = [
            SELECT LastName, FirstName
            FROM User
            WHERE IsActive = false AND LastModifiedDate >= :yesterday AND LastModifiedDate < :System.today()
        ];

        // Query for newly activated 'Tester' users
        List<User> newTesters = [
            SELECT LastName, FirstName
            FROM User
            WHERE IsActive = true AND UserRole.Name = 'Tester'
        ];

        updatePicklistField(deactivatedUsers, newTesters);
    }

    private static void updatePicklistField(List<User> deactivatedUsers, List<User> newTesters) {
        HttpRequest req = new HttpRequest();
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        req.setHeader('Content-Type', 'application/json');
        req.setEndpoint(URL.getOrgDomainURL().toExternalForm() + '/services/data/v60.0/tooling/sobjects/CustomField/00N8L000000vCcg');
        req.setMethod('PATCH');

        // Construct the metadata changes for deactivation and addition
        List<Wrapper> picklistValuesWrapped = new List<Wrapper>();
        List<Map<String, Object>> picklistValues = new List<Map<String, Object>>();

        for (User u : deactivatedUsers) {
            picklistValuesWrapped.add(new Wrapper(new Map<String, Object>{
                'isActive' => false,
                'valueName' => u.LastName + ', ' + u.FirstName    
            }));
        }        

        for (User u : newTesters) {
            picklistValuesWrapped.add(new Wrapper(new Map<String, Object>{
                'isActive' => true,
                'valueName' => u.LastName + ', ' + u.FirstName    
            }));
        }

        // Sort picklistValuesWrapped based on 'valueName'
        picklistValuesWrapped.sort();

        for(Wrapper wrapper: picklistValuesWrapped) {
            picklistValues.add(wrapper.value);
        }

        // Picklist metadata
        Map<String, Object> value = new Map<String, Object>{
            'sorted'=> true,
            'value' => picklistValues
        };

        Map<String, Object> valueSetDefinition = new Map<String, Object>{
            'valueSetDefinition' => value
        };

        // Label...
        Map<String, Object> valueSet = new Map<String, Object>{
            'label' => 'Test Players1',
            'type' => 'Picklist',
            'valueSet' => valueSetDefinition
        };

        // FullName...
        Map<String, Object> fieldMetadata = new Map<String, Object>{
            'Metadata' => valueSet,
            'FullName' => 'Activity.Test_Players1__c'
        };

        req.setBody(JSON.serialize(fieldMetadata));
       
        Http http = new Http();
        HttpResponse res = http.send(req);
       
        if (res.getStatusCode() != 200) {
            System.debug('Error from Tooling API: ' + res.getBody());
            System.debug('Field Metadata:  ' + JSON.serialize(fieldMetadata));
        }
    }
}

Thank you very much for any help you can give.

1 Answer 1

1

The UI uses the sorted property to override the input order and alphabetize the values according to their label. This is a UI-only feature. If you want to do this in code, you'll have to sort the values yourself. You can use the Comparable Interface to write a wrapper class that can leverage List.sort.

public class Wrapper implements Comparable {
  Map<String, Object> value;
  Wrapper(Map<String, Object> value) {
    this.value = value;
  }
  public Integer compareTo(Object o) { // Wrapper
    return value.get('label').compareTo(((Wrapper)o).value.get('label'));
  }
} 

Which you'd change your code to use this wrapper:

List<Wrapper> picklistValuesWrapped = new List<Wrapper>();
picklistValuesWrapped.add(new Wrapper(new Map<String, Object>{
    'isActive' => false,
    'valueName' => u.LastName + ', ' + u.FirstName,
    'recordTypes' => recordTypesPayload
}));

Then sort:

picklistValuesWrapped.sort();

And finally extract:

for(Wrapper wrapper: picklistValuesWrapped) {
  picklistValues.add(wrapper.value);
}
7
  • sfdcfox - you once again are amazing ! So, do I still use picklistValues - I just don't populate it until the end with all of the values from picklistValuesWrapped list essentially ? Am I reading that correctly ? Is there a reason I need two different lists ? And the Wrapper is a separate class all by itself ?
    – Zoom_v
    Commented May 10 at 15:59
  • 1
    @Zoom_v (a) Yes, the extract part at the end gets the values into picklistValues. I did this to minimize the amount of code you need to modify later. (b) To implement custom sorting, we currently need to use a custom class, hence the two lists. I heard that we'll have a better way in some future release, though.
    – sfdcfox
    Commented May 10 at 16:50
  • I apologize,I'm having difficulty implementing your solution into my current solution. I made my Wrapper class separate. But now I'm trying to put in your other portions into my class. I'm not sure if I'm doing what you had intended. I'm trying to add the rest to my current PicklistValuesUpdatePlayer class to refer to the Wrapper class. It seems like the picklistValuesWrapped.add(new Wrapper(new Map... portion should be made separate from the portion of the current picklistValues.add(new Map<String, Object>'isActive' but the new portion gets a variable does not exist 'u' error.
    – Zoom_v
    Commented May 13 at 17:30
  • I would update my original post to show my currently updated class but I don't know if that would only confuse you as opposed to the original. Again, I apologize for that. I really appreciate all of your help. @sfdcfox
    – Zoom_v
    Commented May 13 at 17:32
  • @Zoom_v You're free to edit the question, most people usually add the edits at the bottom to avoid confusion. I'll be happy to edit my answer.
    – sfdcfox
    Commented May 13 at 17:36

You must log in to answer this question.

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