6

I have a Map in custom controller as follows

Map<String, SelectOption[]> mapSelectOption;

and populate this Map as follows in constructor of custom controller

Schema.DescribeSobjectResult R = Account.sObjectType.getDescribe();

//Initialize map to store each object and its fields
mapSelectOption = new Map<String, SelectOption[]>();

//Fetch all child relations for Account
List<Schema.ChildRelationship> C = R.getChildRelationships(); 

Integer j = 0;
//Iterate through all Child objects
for(Schema.ChildRelationship ch : C){

    //In case child object is a custom setting ignore it
    if(!ch.getChildSObject().getDescribe().isCustomSetting()){
        //Describe Each child object, add object name and corresponding fields to a map
        Map<String, Schema.SobjectField> fields = (ch.getChildSobject()).getDescribe().fields.getMap();

        SelectOption[] tempList = new SelectOption[fields.size()];
        Integer i = 0;
        for(Schema.SObjectField s : fields.values()){
            Schema.DescribeFieldResult fieldDescribe = s.getDescribe();
            tempList[i] = new SelectOption(fieldDescribe.getName(),fieldDescribe.getName(), false);
            i++;
        }
        if(i > 0) {
            mapSelectOption.put('key'+j,tempList);
        }
        j++;
    }
}

I am using a custom component from this repo.

This custom component has two attributes of SelectOption[] as type

<apex:attribute name="leftOption" description="Options list for left listbox." type="SelectOption[]" required="true" assignTo="{!leftOptions}" />

<apex:attribute name="rightOption" description="Options list for right listbox." type="SelectOption[]" required="true" assignTo="{!rightOptions}" />

and here is controller code from where the assignTo will call the setter method of leftOptions.

/*
 * MultiselectController synchronizes the values of the hidden elements to the
 * SelectOption lists.
 */
public with sharing class MultiselectController {

    // SelectOption lists for public consumption
    public SelectOption[] leftOptions { get; set; }
    public SelectOption[] rightOptions { get; set; }

    // Parse &-separated values and labels from value and 
    // put them in option
    private void setOptions(SelectOption[] options, String value) {
        options.clear();
        String[] parts = value.split('&');
        for (Integer i=0; i<parts.size()/2; i++) {
            options.add(new SelectOption(EncodingUtil.urlDecode(parts[i*2], 'UTF-8'), 
              EncodingUtil.urlDecode(parts[(i*2)+1], 'UTF-8')));
        }
    }

    // Backing for hidden text field containing the options from the
    // left list
    public String leftOptionsHidden { get; set {
           leftOptionsHidden = value;
           setOptions(leftOptions, value);
        }
    }

    // Backing for hidden text field containing the options from the
    // right list
    public String rightOptionsHidden { get; set {
           rightOptionsHidden = value;
           setOptions(rightOptions, value);
        }
    }
}

Now, I try to use this component in my Visualforce page as follows

<apex:repeat value="{!mapSelectOption}" var="mapKey">
    <c:MultiselectPicklist leftLabel="Available fields" leftOption="{!mapSelectOption[mapKey]}" rightLabel="Selected fields" rightOption="{!mapSelectOption[mapKey]}" size="14" width="150px"/>
</apex:repeat>

It results in following error

Cannot convert the value of '{!leftOptions}' to the expected type.

Also, I have tried following code to see if the Map is populated correctly and I see the results as per the attached image.

<apex:repeat value="{!mapSelectOption}" var="mapKey">
    <apex:outputLabel>{!mapKey}</apex:outputLabel>
    <apex:selectList size="10">
        <apex:selectOptions value="{!mapSelectOption[mapKey]}"/>
    </apex:selectList>
    <br />
</apex:repeat>

enter image description here

PS: I want to understand what is the difference between passing {!mapSelectOption[mapKey]} to the custom component and passing the same to value attribute of an apex:selectOptions tag where the later accepts it and the former results in error.

Any help is much appreciated.

3
  • I have copied your code into my own dev org and got exactly the same error. I haven't been able to figure it out yet either but just wanted to confirm that the problem you are having is perfectly valid. Commented May 15, 2014 at 22:50
  • Also I have tried changing mapSelectOption to a List<List<SelectOption>> however I still got exactly the same error message. Commented May 15, 2014 at 22:51
  • Thank you for looking into this. Even, I tried List<List<SelectOption>> when I was working on this, but it didn't work.
    – jagmohan
    Commented May 16, 2014 at 0:54

1 Answer 1

4

There certainly seems to be some weird bug going on to do with generic types (e.g. using a list or map). After a bit of experimentation I found a workaround, and that is to use a wrapper class as follows:

public class OptionsList {
    public List<SelectOption> options { get; set; }

    public OptionsList() {
        this.options = new List<SelectOption>();
    }

    public void push(SelectOption opt) {
        this.options.add(opt);
    }
}

At the top of your custom controller you can now create a list of this wrapper class:

public List<OptionsList> optionsLists { get; set; }

And your page can iterate over this as follows:

<apex:repeat value="{!listOptions}" var="ol">
        <c:MultiselectPicklist leftLabel="Available fields" leftOptions="{!ol.options}" rightLabel="Selected fields" rightOptions="{!ol.options}" size="14" width="150px"/>
</apex:repeat>

Here is a link to a gist containing your code with my adjustments: https://gist.github.com/lukemcfarlane/a90a78e3a4b1d05e34c2

1
  • Thank You. I will give it a try and accept your answer. And, the project in which I needed this has already been completed, I handled this stuff using JavaScript/HTML.
    – jagmohan
    Commented May 19, 2014 at 4:14

You must log in to answer this question.

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