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
Zoom_VZoom_V 

Picklist select options from a multi-value field

I would like to use the values of a multi-value field of one record the select options of another record's multi-select picklist. I am currently doing something very similar to this with a query which is returning field values from multiple records in a relationship. 

 

Here is my current code which pulls the value from a single field from several records : 

public class MycontrollerSFDCBETA2b
{
private final Contract_Overview__c contract;
public String rightOptionsHidden { get; set; }
public String leftOptionsHidden { get; set; }
public String selectedMulPickKeyTech{get;set;} 
public string names{get;set;}
public string accountid{get;set;}
public String message { get; set; }
public List<SelectOption> options { get; set; }
public List<SelectOption> selectedSubs2 { get; set; }
    
    public MycontrollerSFDCBETA2b(apexpages.standardcontroller controller)
        {
        this.contract = (Contract_Overview__c) controller.getRecord();
        }

    public pageReference  execute()
        {
        return null;
        }

    public list<selectoption> getitems()
        {
        accountid=contract.Account__c;
        
        selectedMulPickKeyTech=contract.Subsidiaries_On_Contract__c;
        selectedMulPickKeyTech=selectedMulPickKeyTech.replace('[','');                
        selectedMulPickKeyTech=selectedMulPickKeyTech.replace(']','');

        String[] selectedvalues = selectedMulPickKeyTech.split(',');
        selectedSubs2 = new list<SelectOption>();
        for (String selectedvalue: selectedvalues) 
            {
            selectedSubs2.add(new SelectOption(selectedvalue,selectedvalue));
            }
    
        List<selectoption> options= new list<selectoption>();
            if(accountid != null)
            {
            account a =[select name , (select name from Subsidiaries_and_Brands__r) from account where id =:accountid];
                for(SubsidiariesAndBrands__c s : a.Subsidiaries_and_Brands__r)
                    {
                    options.add(new SelectOption(s.name,s.name));
                    }
            }
            else
            options.add(new SelectOption('None','None'));
            return options;
        }
    
    public void save()
        {
        message = null ;       
        Boolean first = true;
           for ( SelectOption so : selectedSubs2 ) 
            {
                if (first) 
                    {
                    message = message ;
                    }
                    message = message + ', ' + so.getValue() ;
                    first = false;
            }        
                message = message.removeStart('null, ');
                message = message.normalizeSpace();
                message = '['+message+']';
                contract.Subsidiaries_On_Contract__c=message;
        
        update contract;
                       
        }
}

 

From that code I am using !items as the select options of a picklist on VF. 

 

I'd like to accomplish the same thing by querying a single record's multi-value field. I have a very VERY generalized idea how to accomplish it. I think I need to take some kind of approach like this : 

String[] picklistlines =new String[]{};
String selectedMulPickKeyTech{get;set;} 

public string contractid{get;set;}

public list<selectoption> getitems()
            {
            contractid=contract.Contract_Title__c;

contract = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid];

selectedMulPickKeyTech=contract.Subsidiaries_On_Contract__c;


					
picklistlines = selectedMulPickKeyTech.split('\n');

 

But I don't know how to properly build the list with the For statement. I also don't think that query will work properly.

 

If you can give me any help I would really appreciate it. I feel like I'm very close to the solution here.

 

Thank you very much.



Best Answer chosen by Admin (Salesforce Developers) 
Saurabh DhobleSaurabh Dhoble

Sure , no problem, you can give "kudos" to me my profile if this was helpful.

 

Regarding your error, the selectList needs to be exposed as property of the class in order to use in a VF page .. change your code like this --

 

public class MycontrollerContractTerms
{
private final Contract_Overview__c contract;
public String rightOptionsHidden { get; set; }
public String leftOptionsHidden { get; set; }
public String selectedMulPickKeyTech{get;set;} 
public string names{get;set;}
.
.
.
.
public List<SelectOption> selectList
{
     get
     {
           if (selectList == null)
           {
                selectList = new List<SelectOption>();
           }
           return selectList;
     }
     set
     {
           selectList = value;
     }
}
..
..
..
..
..
..
Rest of your code here

 Keep in mind - you cannot use an object in a Visualforce page if it is not exposed as a property (with get /set methods).

All Answers

Saurabh DhobleSaurabh Dhoble

Not sure what your issue is, you already did the hard part by creating a comma-seperated list of all subsidiary names. From what I understand, you need to do it in reverse, i.e. build a picklist based on the comma-seperated string. Here's the code for that - let me know if this is what you needed or was it something else.

 

String Subsidiaries_On_Contract = '[Test1,Test2,Test3,Test4]';
String commaSeperatedList = Subsidiaries_On_Contract.right(
    							Subsidiaries_On_Contract.length()-1
    						);
commaSeperatedList = commaSeperatedList.left(commaSeperatedList.length()-1);
List<String> splitList = commaSeperatedList.split(',');
List<SelectOption> selectList = new List<SelectOption>();
for (String s: splitList)
{
    selectList.add(new SelectOption(s,s));
}

System.Debug('SelectList Length is : ' + selectList.size());

 

Zoom_VZoom_V

Thank you very much for your response. I'm really confused by your suggestions and how they would fit into my code. I'm also a little confused because you seem to have given one of the strings the same name as the field. I also don't understand what you mean by equating it to '[Test1,Test2,Test4]';

 

Can you show it to me as it could be adapted from the code I have at the top in which I am pulling a field value from multiple records ?

 

 

 

Also, I'm not sure if my new query would be correct. Can you tell me ? :

 

contractid=contract.Contract_Title__c;
contract = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid];

 

Thank you so much for your help. I really appreciate your time and effort.

Saurabh DhobleSaurabh Dhoble

Sure, I have modified your code here to include the fix - let me know if this is what you are looking for. I have put in comments to help understand the code better.

 

String[] picklistlines =new String[]{};
String selectedMulPickKeyTech{get;set;} 

public string contractid{get;set;}

public list<selectoption> getitems()
{
        contractid=contract.Contract_Title__c;

        //No need to create a seperate contact variable, you can just select from the query
        selectedMulPickKeyTech = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid].Subsidiaries_On_Contract__c;

        //At this point, selectedMulPickKeyTech has a comma-seperated list of names, something like '[Account Name 1, Account Name 2, Account Name 3......and so on]'

        //Now remove the starting and ending brackers [ ]
        selectedMulPickKeyTech = selectedMulPickKeyTech.right(selectedMulPickKeyTech.length()-1);

        selectedMulPickKeyTech = selectedMulPickKeyTech.left(selectedMulPickKeyTech.length()-1);

       //Build a List<SelectOption> by breaking down the comma-seperated list into individual list options
       List<String> splitList = selectedMulPickKeyTech.split(',');
       List<SelectOption> selectList = new List<SelectOption>();
       for (String s: splitList)
       {
              selectList.add(new SelectOption(s,s));
       }
       

       //By now, you have the List<SelectOption> ready. Print out how many items it has.
       System.Debug('SelectList Length is : ' + selectList.size());


      //You can now set the "selectList" as the source for a picklist on your page.

 

Zoom_VZoom_V

Thank you so much Saurabh !!!

 

I was able to apply the code & save it. However, my VF page is giving me an error saying selectList is an unknown property of my class. 

 

Should I not be naming !selectList as my picklist value ? Should I be naming !items instead ? Is it a case in which I am naming a parameter somewhere ?

Here is the code as it stands now : 

public class MycontrollerContractTerms
{
private final Contract_Overview__c contract;
public String rightOptionsHidden { get; set; }
public String leftOptionsHidden { get; set; }
public String selectedMulPickKeyTech{get;set;} 
public string names{get;set;}
public string accountid{get;set;}
public String message { get; set; }
public List<SelectOption> options { get; set; }
public List<SelectOption> selectedSubs2 { get; set; }

String[] picklistlines =new String[]{};
public string contractid{get;set;}

    
    public MycontrollerContractTerms(apexpages.standardcontroller controller)
        {
        this.contract = (Contract_Overview__c) controller.getRecord();
        }

    public pageReference  execute()
        {
        return null;
        }

    public list<selectoption> getitems()
        {
        accountid=contract.Account__c;
        contractid = contract.Contract_Title__c;
selectedMulPickKeyTech = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid].Subsidiaries_On_Contract__c;

selectedMulPickKeyTech = selectedMulPickKeyTech.right(selectedMulPickKeyTech.length()-1); selectedMulPickKeyTech = selectedMulPickKeyTech.left(selectedMulPickKeyTech.length()-1); List<String> splitList = selectedMulPickKeyTech.split(','); List<SelectOption> selectList = new List<SelectOption>(); if(accountid != null) { for (String s: splitList) { selectList.add(new SelectOption(s,s)); } } else selectList.add(new SelectOption('None','None')); return selectList; } public void save() { message = null ; Boolean first = true; for ( SelectOption so : selectedSubs2 ) { if (first) { message = message ; } message = message + ', ' + so.getValue() ; first = false; } message = message.removeStart('null, '); message = message.normalizeSpace(); message = '['+message+']'; contract.Subsidiaries_On_Contract__c=message; update contract; } }

 

 

Thank you so much for your time & effort. You've been a huge help and I am very grateful. 

 



 

 

Saurabh DhobleSaurabh Dhoble

Sure , no problem, you can give "kudos" to me my profile if this was helpful.

 

Regarding your error, the selectList needs to be exposed as property of the class in order to use in a VF page .. change your code like this --

 

public class MycontrollerContractTerms
{
private final Contract_Overview__c contract;
public String rightOptionsHidden { get; set; }
public String leftOptionsHidden { get; set; }
public String selectedMulPickKeyTech{get;set;} 
public string names{get;set;}
.
.
.
.
public List<SelectOption> selectList
{
     get
     {
           if (selectList == null)
           {
                selectList = new List<SelectOption>();
           }
           return selectList;
     }
     set
     {
           selectList = value;
     }
}
..
..
..
..
..
..
Rest of your code here

 Keep in mind - you cannot use an object in a Visualforce page if it is not exposed as a property (with get /set methods).

This was selected as the best answer
Zoom_VZoom_V

That worked ! Thank you so much Saurabh ! 

 

That was really fantastic of you. I appreciate your time and effort so much !

 

Take care.

Zoom_VZoom_V

Ok, maybe I spoke too soon. It is not returning any results for the select list. This is what my code looks like after adding your get\set suggestions. 

 

Can you see anything wrong with this code ? I'm not getting an error from it. 

 

public class MycontrollerContractTerms
{
private final Contract_Terms__c contract;
public String rightOptionsHidden { get; set; }
public String leftOptionsHidden { get; set; }
public String selectedMulPickKeyTech{get;set;} 
public string names{get;set;}
public string accountid{get;set;}
public String message { get; set; }
public List<SelectOption> options { get; set; }
public List<SelectOption> selectedSubs2 { get; set; }

String[] picklistlines =new String[]{};
public string contractid{get;set;}

public List<SelectOption> selectList
{
     get
     {
           if (selectList == null)
           {
                selectList = new List<SelectOption>();
           }
           return selectList;
     }
     set
     {
           selectList = value;
     }
}
    
    public MycontrollerContractTerms(apexpages.standardcontroller controller)
        {
        this.contract = (Contract_Terms__c) controller.getRecord();
        }

    public pageReference  execute()
        {
        return null;
        }

    public list<selectoption> getitems()
        {
        accountid=contract.Account__c;
        contractid = contract.Contract_Title__c;
selectedMulPickKeyTech = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid].Subsidiaries_On_Contract__c;

selectedMulPickKeyTech = selectedMulPickKeyTech.right(selectedMulPickKeyTech.length()-1);
selectedMulPickKeyTech = selectedMulPickKeyTech.left(selectedMulPickKeyTech.length()-1);
        
    List<String> splitList = selectedMulPickKeyTech.split(',');
       List<SelectOption> selectList = new List<SelectOption>();
       
            if(accountid != null)
            {
            for (String s: splitList)
       {
              selectList.add(new SelectOption(s,s));
       }
            }
            else
            selectList.add(new SelectOption('None','None'));
            return selectList;
        }
    
    public void save()
        {
        message = null ;       
        Boolean first = true;
           for ( SelectOption so : selectedSubs2 ) 
            {
                if (first) 
                    {
                    message = message ;
                    }
                    message = message + ', ' + so.getValue() ;
                    first = false;
            }        
                message = message.removeStart('null, ');
                message = message.normalizeSpace();
                message = '['+message+']';
                contract.Subsidiaries_Included_On_Terms__c=message;
        
        insert contract;
                       
        }
}

Should I be using !items as the list reference or !selectList ? I'm using !selectList but I'm not sure if that is correct.

 

The object I'm in is Contract Terms. It's pulling from an object named Contract Overview.  

 

Thanks again Saurabh. 

Saurabh DhobleSaurabh Dhoble

Sure, so there could be multiple things going on here - can you also paste your Visualforce page code so I can understand better.

 

Also, I'm putting in some debug statements in the code - this will output the value of the variable to the log file during code execution - 

 

    public list<selectoption> getitems()
        {
        accountid=contract.Account__c;
        contractid = contract.Contract_Title__c;
selectedMulPickKeyTech = [SELECT Subsidiaries_On_Contract__c FROM Contract_Overview__c where Contract_Overview__c.id=:contractid].Subsidiaries_On_Contract__c;

System.Debug(selectedMulPickKeyTech);

selectedMulPickKeyTech = selectedMulPickKeyTech.right(selectedMulPickKeyTech.length()-1);
selectedMulPickKeyTech = selectedMulPickKeyTech.left(selectedMulPickKeyTech.length()-1);

 I believe you should continue binding to !items - paste your VF code here and I can help dig into it further.

Zoom_VZoom_V

I don't think the problem is in the VF page because it's essentially the same VF page I'm using for other objects which are using the method I put in the original post but I'll post it in here anyway. 

 

When I use !items it will at least display the "None" in the picklist options, which makes me think you're on the right track where you put the debug because I have a feeling the problem is the query not returning anything. 

 

So, I may have the query set up incorrectly. I'm sure you understand this, but just to make sure you know what I'm attempting to do : I'm attempting to query the Contract_Overview__c record whose  Name field is equal to the Contract_Title__c field of the current Contract_Title__c record. The Contract_Title__c field is a lookup to the Contract_Overview.Name field. In the query it is referred to as the Contract_Overview.id field but I'm assuming that is ok since the Contract_Title__c field is a lookup to the field and is being properly populated upon creation of the record.

 

I tried using the debug you put in to see if  selectedMulPickKeyTech was coming back with a result but the debug result wasn't showing up in my log in the Developer Console. 

 

Here is the VF page code. Again, I don't think it is the problem since I'm using it for so many other objects, but I could be wrong because the new record isn't even being saved. 



<apex:page standardcontroller="Contract_Terms__c" extensions="MycontrollerContractTerms">
    <apex:sectionheader title="{!$ObjectType.Contract_Terms__c.label} Edit" subtitle="{!IF(ISNULL(Contract_Terms__c.name), 'New Contract Terms',Contract_Terms__c.name)}"/>
    <apex:form >
        <apex:pageblock mode="edit" title="{!$ObjectType.Contract_Terms__c.label} Edit">
            <apex:pageblockbuttons >
                <apex:commandbutton value="Save" action="{!Save}"/>
                <apex:commandbutton value="Cancel" action="{!Cancel}"/>
            </apex:pageblockbuttons>

            <!-- ********** Output Panel for Record Type : Americas Standard **********  -->
            <apex:outputpanel rendered="{!OR(ISNULL(Contract_Terms__c.RecordTypeId),CASESAFEID(Contract_Terms__c.RecordTypeId)='012200000008d7rAAA')}">
                <apex:pageblocksection title="Contract Terms" columns="2">
                <apex:inputfield value="{!Contract_Terms__c.Contract_Title__c}" required="false"/>
                        <apex:inputfield value="{!Contract_Terms__c.Account__c}" required="true"/>                   
        <apex:inputfield value="{!Contract_Terms__c.Contract_Status__c}" required="false"/>
                  
                <apex:outputtext value="Subsidiaries Included On Terms" />  
                         


     
                <apex:pageBlockSection >
             <apex:pageBlockSectionItem id="selPanel"> 
          
                <c:MultiselectPicklist leftLabel="Available Subsidiaries"
                    leftboxatt="{!items}"
                    rightLabel="Selected Subsidiaries"
                    rightboxatt="{!selectedSubs2}"
                    size="10"
                    width="150px"/>
                                  
             </apex:pageBlockSectionItem> 
                          
             <apex:pageBlockSectionItem >
             <apex:outputLabel >Subs Selected:</apex:outputLabel>   
                 <apex:outputtext value="{!selectedSubs2}" id="field2"/> 
             </apex:pageBlockSectionItem>
        
        </apex:pageBlockSection>  

 

That's not the entire page, but it's everything that involves the picklist. 

 

Thank you again for all of your help Saurabh. I know I'm asking a lot here and you've really put a great amount of effort into helping me. I really appreciate it.

 

Take care.

 

 

 

Zoom_VZoom_V

Ok, here's the new development and something really weird : It will the list into the picklist options BUT only after the Save has been hit - and then it's not saving the new record.

 

That's where I'm standing now. I guess for some reason the query isn't executing until after Save, but I can't figure out why it isn't saving the new record.

 

craziness.

Saurabh DhobleSaurabh Dhoble

So there are multiple things going on here, and you need to methodically address each one.

First, The system.debug statement should be writing out the value of the variable in the logs. If you cannot find it, try adding special characters to make the log message stand out, something like this -

 

System.Debug('*****************************************' + selectedMulPickKeyTech + '*********************************');

 

Next, you need to understand the program flow. Here's what is happening :-

1. The page loads up.

2. When the VF page tries to render the list, it realizes it needs to get the value of the !Items variable.

3. It goes into the !Items variable, and runs the query to get the "Subsidiaries_On_Contract__c" field. Since you have not really saved this field yet, the query returns an empty string. Once you get the Debug working, you will see that it is returning an empty string.

4. So, it renders the page with an empty list.

5. Then you hit the Save button - at this point, it calls the Save() method- this method goes through all the subsidiaries, and populates a comma-seperated list of all subsidiary names in the "Subsidiaries_On_Contract__c" field.

6. After the Save() method is executed, the page now starts rendering again - at this point, it again calls the !Items variable, which again runs the query to get "Subsidiaries_On_Contract__c". This time, the query returns a value, you can see this again with the Debug statement.

7. The code then creates the SelectList, based on the values in the "Subsidiaries_On_Contract__c", and returns a SelectList with a few items.

8. The page renders back, and this time, it has values in the SelectList.

 

You need to seperate out the logics -  I don't think you should run a SOQL query to get the entire list in the "Save()" method every time. In this method, you should simply take whatever has been selected in the multi-select picklist, create a comma-seperated list of those items, and save those to the database.

Zoom_VZoom_V

Yes, I understand what you are saying. I got the whole thing to work properly with the code I put in the original post. In that case the code is for editing an already saved page, so the code would run the query against a field which had already been populated. I was hoping I would be able to do the same thing with this object when creating a new record becauses it would be pulling in the value of the field from the parent. I thought maybe doing a re-render (onchange) on the output panel might do the trick, but I guess not. Is there a way to execute that query upon creation of the new record ?

 

Yes, I'm attempting to create a comma-separated list from them. That's what I was doing with selectedSubs2 in the coding in the original post. So, in this one I'm attempting to do the same thing in this current code.

 

I also understand what you're saying that I should only be pulling the items which have not yet been selected. That was going to be my next task - to compare !items to !selectedSubs2 and only bring the values not in !selectedSubs2.

 

But for now I just want to be able to have the query run against the value being automatically pulled into the Contract_Title__c field. Is there no way to do that without saving the record first ? Do you have any ideas on why that code might not be saving ? 

 

I'm continuing to debug. I really appreciate any feedback you can give. 

 

Thank you very much.