8

I think I may have found a bug with iterating over a set in spring'14.

So I have some code that creates a set (using set so it will be unique) and then on the page it iterates over the set using an apex:repeat. The problem is that it wont save. If I change the set to a list it saves and works fine. I know (or am pretty sure) I have been able to use sets in the past with apex:repeat but now I cannot. Here is the code (simplified) and the errors:

public class CreateOrders {

  public Set<Item__c> selectedItems {get; set;}

  public CreateOrders() {
    selectedItems = new Set<Item__c>();
    for (Item__c i : findItems()) {
      selectedItems.add(i);
    }
  }
}

then on the page:

<apex:repeat value="{!selectedItems}" var="itm">
  <apex:outputfield value="{!itm.Name}" />
</apex:repeat>

and the resulting error is: Save error: Could not resolve the entity from apex:outputField value binding '{!itm.Name}'. apex:outputField can only be used with SObjects, or objects that are Visualforce field component resolvable.

and when I try removing the apex:outputfield by using apex:outputtext or nothing like so:

<apex:repeat value="{!selectedItems}" var="itm">
  <apex:outputtext value="{!itm.Name}" />
</apex:repeat>

OR

<apex:repeat value="{!selectedItems}" var="itm">
  {!itm.Name}
</apex:repeat>

I get this error: Save error: Unknown property 'SetValue.Name'

and its the same with any field/object. But when I switch the Set over to a List it works without any issues...

UPDATE

So on a hunch I checked the version, and it was on 28. When I upgraded it to 29, it allowed me to save with apex:outputfield only, but on refresh of the page I still got the same errors:

Could not resolve the entity from apex:outputField value binding '{!itm.Name}'. apex:outputField can only be used with SObjects, or objects that are Visualforce field component resolvable.

and it still wouldnt let me save if I changed the apex:outputfield to apex:outputtext or used no apex tags it would still not save and give me the error:

Save error: Unknown property 'SetValue.Name'

On versions older than 29 (20-28 that I have tested) they all error like 28, 29 is the only one with a slightly different behavior.

When saving with just {!itm} it allows the save to happen, and the page just shows the Id of the Item.

  • Did you try to save with a set property + vf repeater as older api versions ? – Samuel De Rycke Feb 24 '14 at 19:49
  • see updated question, but both version 28 and 29 wont work with sets/apex:repeat – SalesForceGirl Feb 24 '14 at 19:55
  • How about displaying just {!itm}, this also caused problems? – Artur Kępczyński Feb 24 '14 at 20:05
  • no, that allows the save to happen, and on the page, it shows the item Id.. but this only works if i dont use apex:outputfield, apex:outputtext works and using no tags works – SalesForceGirl Feb 24 '14 at 20:15
  • Though I can see using a list and using list.addall(set) as workaround, I confirm the same behavior with my developer account too. Lists are working fine, but sets are not with apex:repeat tag – Rao Feb 24 '14 at 20:16
6

I don't think this is a new behaviour in Spring 14.

In the discussion forums - Table rows repeating for each Child Record present in Parent to Child Query there is a comment from @bob-buzzard in 2011:

It seems to be a problem when the set contains sobjects - I've just checked back on mine and they've been primitives. It smacks that the "SetValue" in the page (sounds low-level possibly a java class) can convert to a string for display if its a primitive, but not when a complex object.

There is an example of using a primitive Set with an apex:repeat in the answer Peter Knolle provided to another question.


As an alternative to using a Set you could instead use a Map (assuming your records have been inserted and have an Id). Then use the syntax from Referencing Apex Maps and Lists to drive the repeat over the maps keys and lookup the corresponding value.

Controller:

public class CreateOrders {
    public Map<Id, Item__c> selectedItems {get; set;}

    public CreateOrders() {
        selectedItems = new Map<Id, Item__c>();
        for (Item__c i : findItems()) {
            selectedItems.put(i.Id, i);
        }
    }
}

Visualforce page:

<apex:repeat value="{!selectedItems}" var="itm">
    <apex:outputfield value="{!selectedItems[itm].Name}" />
</apex:repeat>
3

I will try to confirm this but I think tis is caused because set is non-ordered collection of data and you just can't get element number [i] and ask it for values like repeat block try to do - and thats why it work with list

For now lets be patient and wait for one of MVP to speak :)

  • You can use a Set as the value in a repeat. See Apex Repeat Using Set Collection. It might be a special Case for sObjects. – Daniel Ballinger Feb 24 '14 at 23:38
  • Here is a 2011 comment from MVP @bob-buzzard: "It seems to be a problem when the set contains sobjects - I've just checked back on mine and they've been primitives. It smacks that the "SetValue" in the page (sounds low-level possibly a java class) can convert to a string for display if its a primitive, but not when a complex object." – Daniel Ballinger Feb 24 '14 at 23:52
  • Thats kinda what I suspected... Thanks for finding this! :) – Artur Kępczyński Feb 25 '14 at 4:34

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.