+ Start a Discussion
kevoharakevohara 

Visualforce Dynamic Binding issue with Map Collections?

I feel like I periodically run into this issue and feel quite certain that this is a bug. Maybe someone can help.

 

In my controller, I have a Map that looks like this...

 

Map<String, List<CustomObjectWrapper>> objMap;

 My key is a category field for my Custom Object wrapper which looks like this...

 

public class CustomObjectWrapper {
  public boolean selected {get; set;}
  public Custom_Object__c customObject {get; set;}
}

 

 What I am doing in my Visualforce page is create a pageBlockTable for each of the keys (my category) in the map. The values are put into a table and the Description__c field is available for editing. Here is an example.

 

<apex:repeat value="{!objMap}" var="category" >
  <apex:pageBlock title="Category: {!category}">
    <apex:pageBlockTable value="{!objMap[category]}" var="obj">
      <apex:column value="{!obj.customObject.Name}" />
      <apex:column value="{!obj.customObject.Category__c}" />
      <apex:column headerValue="Description">
        <apex:inputField value="{!obj.Description__c}"/>
      </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlock>
</apex:repeat>

 

Now here is the weird part...

 

I have save button on the page that simply updates the records. 99% of the time the records update with no problem. However, when there are two keys in the map of category "VOE" and "Reference", the controller misplaces the values for the Description__c field. The descriptions get saved on the incorrect records. Anything other than the combination of those two keys works fine! Completely bizarre.

 

I've read a bit about some dynamic VF issues with Maps but I don't see anythin definitive in the "Known Issues" list on the community site. Does anyone know if this is indeed a bug? And if so, are there any workarounds?

Best Answer chosen by Admin (Salesforce Developers) 
aballardaballard

Almost.  But you either need to make that list be stored in a member field of your class so it is included in viewstate, or you need to sort the list when you create it in getKeys().  

 

Otherwise you will have the same problem... as you have written it , when the page is posted back it would get a new copy of the key list in the possibly-different order. 

 

The first approach, making it part of viewstate, would not be good if the list is large. 

 

I think you could just use  

        new List<String>().addAll(objMap.keySet()).sort() ;

All Answers

aballardaballard

Yeah, there is an issue here.   The problem is that the "order" of map elements is undefined and sometimes turns out to be different on the postback to what it was when the page was generated (so data posted back to row one goes to row one but this now contains different data....)

There is a work item to fix this but currently not fixed.

 

 

The workaround is to create a list with the keys (in whatever order you want them), and iterate over that list instead of over the map. 

kevoharakevohara

Thank you so much for the response. Are you saying that I can still use the map within the Visualforce page but use a separate list for the keys?

 

Something like this in the controller?

 

public List<String> getKeys() {
  List<String> keys = new List<String>();
  for(String s : objMap.keyset()) {
    keys.add(s);
  }
  return keys;
}

 

Then just put that List into the apex:repeat but access the Map values using the List values? 

kevoharakevohara

Actually I just tried that and it doesn't work.

aballardaballard

Almost.  But you either need to make that list be stored in a member field of your class so it is included in viewstate, or you need to sort the list when you create it in getKeys().  

 

Otherwise you will have the same problem... as you have written it , when the page is posted back it would get a new copy of the key list in the possibly-different order. 

 

The first approach, making it part of viewstate, would not be good if the list is large. 

 

I think you could just use  

        new List<String>().addAll(objMap.keySet()).sort() ;

This was selected as the best answer
kevoharakevohara

That did it! Thanks so much for the help.

 

Would you mind suggesting that this get added to the Known Issues list? I know others have had this issue.

AlejandroRaigonAlejandroRaigon

This is now available in our Known Issues portal: http://success.salesforce.com/issues_view?id=a1p30000000RmuRAAS

 

Thanks,

Alejandro