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>
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.
Best Answer
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:
At the top of your custom controller you can now create a list of this wrapper class:
And your page can iterate over this as follows:
Here is a link to a gist containing your code with my adjustments: https://gist.github.com/lukemcfarlane/a90a78e3a4b1d05e34c2