6

I have queries pulling all of the information correctly but what I can't seem to find was a way to add new options to a picklist using APEX.

I currently have

Package__c.Products__c.add(new Schema.PicklistEntry(products[j].Name));

Package__c is my custom object, and Products__c is the picklist. products[j] is pulling a list of products pulled from our products page.

And I've tried adding it as a select option, or even casting the variable type.

And this information has to go to the actual picklist within a custom object, and not within a visual force page or anything like that.

  • 2
    That is an administrative capability that I would strongly recommend against exposing to your end users. Can you go into more detail about your use case? – Adrian Larson Feb 9 '15 at 20:44
  • Well currently I need a dynamic picklist that pulls in the entire listing of our products to a custom object to build packages with deal based incentives. That way we can select a few products and save it to a package, and then check these packages against the products in an opportunity. – Cody Beaner Feb 10 '15 at 15:01
  • Are you sure you need a picklist? Why not use a lookup to Product then? – Adrian Larson Feb 10 '15 at 15:05
  • Are there multi-lookups? The person using this needs to be able to select multiple items. – Cody Beaner Feb 10 '15 at 15:35
7

The way to do this is using the Apex MetaData API wrapper as provided by esteemed SFSE colleague Andrew Fawcett here

  1. Running user needs to have Customize Application privilege so you really want this to be an admin type user
  2. Read the examples in the GIT package carefully - there is one for picklists. You need to read the CustomField from the MetaData API first then update, otherwise you'll smash all the existing picklist entries.

The relevant example in the package's MetadataServiceExamples.cls file is here:

public static void updatePicklist()
{
    MetadataService.MetadataPort service = createService();             

    // Read Custom Field
    MetadataService.CustomField customField = 
        (MetadataService.CustomField) service.readMetadata('CustomField', 
            new String[] { 'Lead.picklist__c' }).getRecords()[0];       

    // Add pick list values
    metadataservice.PicklistValue two = new metadataservice.PicklistValue();
    two.fullName= 'second';
    two.default_x=false;
    metadataservice.PicklistValue three = new metadataservice.PicklistValue();
    three.fullName= 'third';
    three.default_x=false;
    customField.picklist.picklistValues.add(two);
    customField.picklist.picklistValues.add(three);     

    // Update Custom Field
    handleSaveResults(
        service.updateMetadata(
            new MetadataService.Metadata[] { customField })[0]);        
}
  • 1
    This is very useful but the associated knowledge needed is outside of my scope. Thank you though! – Cody Beaner Feb 10 '15 at 17:43
  • Okay so I looked into it deeper and decided to have a go at it. The example shows creating a new picklist and updating the created picklist, but what about updating an existing picklist? – Cody Beaner Feb 12 '15 at 16:23
  • @CodyBeaner - I added the code sample from the examples class – cropredy Feb 12 '15 at 17:04
  • I've used the code to completely make a new field and it doesn't even show. Is there a comprehensive tutorial for this? – Cody Beaner Feb 13 '15 at 15:51
  • @CodyBeaner - Hmm -- the Apex wrapper to the metadata API is basically a wrapper on how a REST or SOAP client would use the API. As such, the SFDC doc developer.salesforce.com/docs/atlas.en-us.api_meta.meta/… was the most helpful to me along with the aformentioned examples class. The doc explains the datastructure – cropredy Feb 13 '15 at 20:08
0

Based on your comments, what you really want is a Junction object to Create a Many-To-Many Relationship between Product and your Package Deal object. I might call it something like Package Deal Line Item.

  • This seems like it might be exactly what I need, thanks! – Cody Beaner Feb 10 '15 at 16:26
  • Haha it was tough to figure out what you really needed. Gotta ask the right questions! :) – Adrian Larson Feb 10 '15 at 16:28
  • So for some reason I cannot add a Master relationship to my products? Ideas? – Cody Beaner Feb 10 '15 at 17:31
  • You can't make Product master? Well, a junction can still enable many-to-many with a lookup instead. The pairing is not as rigid, but I think it will suit your needs. – Adrian Larson Feb 10 '15 at 17:32
  • This does't really seem to be what I'm looking for... Is there a way to put the product layout in my custom object the same way it's in opportunity? – Cody Beaner Feb 10 '15 at 17:42
0

@cropredy answer is correct. But there are some changes in MetadataService class. So code given in above answer will not work. Below code will work with latest version of mdapi GitHub repo.

MetadataService.MetadataPort service = createService(); 

MetadataService.CustomField picklistField =(List<MetadataService.CustomField>) service.readMetadata('CustomField', 'Lead.picklist__c').getRecords();

metadataservice.CustomValue two = new metadataservice.CustomValue();
two.fullName= 'second';
two.default_x=false;  

picklistField.valueSet.valueSetDefinition.value.add(two);

MetadataService.SaveResult result = service.updateMetadata( new MetadataService.Metadata[] { picklistField })[0];

In place of PicklistValue we have to use ValueSet. Also we need to make little change in MetadataService Class. We have to replace ValueSet virtual class in Metadatservice with

public class ValueSet {
        public String controllingField;
        public Boolean restricted;
        public MetadataService.ValueSetValuesDefinition valueSetDefinition;
        public String valueSetName;
        public MetadataService.ValueSettings[] valueSettings;
        private String[] controllingField_type_info = new String[]{'controllingField',SOAP_M_URI,null,'0','1','false'};
        private String[] restricted_type_info = new String[]{'restricted',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSetDefinition_type_info = new String[]{'valueSetDefinition',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSetName_type_info = new String[]{'valueSetName',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSettings_type_info = new String[]{'valueSettings',SOAP_M_URI,null,'0','-1','false'};
        private String[] apex_schema_type_info = new String[]{SOAP_M_URI,'true','false'};
        private String[] field_order_type_info = new String[]{'controllingField','restricted','valueSetDefinition','valueSetName','valueSettings'};
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.