2

I have a <p:selectManyCheckbox> inside <ui:repeat>, getting it's items from a List of a certain Object Class (provided by <ui:repeat>-variable) and is supposed to save the chosen items into another List of the same Object Class. But it calls the setter method #{cartBean.setSelectedExtras} only for the last entry (last iteration of <ui:repeat>).

<ui:repeat var="item" value="#{category.items}">
    <p:selectManyCheckbox id="extraCheckbox" value="#{cartBean.selectedExtras}" layout="pageDirection" converter="omnifaces.SelectItemsConverter">  
         <f:selectItems value="#{item.items5}" var="extra" itemLabel="#{extra.name}"/>
    </p:selectManyCheckbox>
</ui:repeat>

Update: I changed the above construct just the way BalusC proposed.
Declaration in backing bean is now:

private List<List<Item>>  selectedExtras   = new ArrayList<List<Item>>();

When I check checkboxes that were created by the first loops of <ui:repeat> and click the <p:commandButton> inside the same <h:form> the setter method of selectedExtras is not called. When I check the checkboxes created in the last loop of <ui:repeat> and click the <p:commandButton> I get an Exception:

javax.el.PropertyNotFoundException: /lightbox-item.xhtml @57,165 value="#{cartBean.selectedExtras[iteration.index]}": null
Lester
  • 1,830
  • 1
  • 27
  • 44
  • you're going to need to post more code than that. Please post some backing bean code. – Catfish Oct 30 '12 at 21:02
  • @Catfish I edited my question. Actually I don't think there is any interesting backing bean code. As you can see now `#{item}` is the variable from `` and `#{cartBean.selectedExtras}` points to simple setter/getter methods for a `List` just as `#{item.items5}` is one and `#{category.items}` is too. – Lester Oct 31 '12 at 09:39

1 Answers1

2

This construct works fine for me.

As mentioned in among others the showcase page, the omnifaces.SelectItemsConverter uses by default the toString() representation of the complex object as converted item value. So if you didn't override the toString() method (so that it still defaults to com.example.SomeClass@hashcode which changes on every instantiation) and the #{item} managed bean is request scoped, then the list would basically be changing on every HTTP request. This would cause a "Validation Error: Value is not valid" error.

If you add

<p:messages autoUpdate="true" />

or

<p:growl autoUpdate="true" />

so that you get all (missing) validation/conversion messages in the UI, then you should have noticed it.

In order to utilize the omnifaces.SelectItemsConverter at its best, you should override the toString() method accordingly so that it returns a fixed and unique representation of the complex object. E.g.

@Override
public String toString() {
    return "Extra[id=" + id + "]";
}

Alternatively, you could put the #{item} managed bean in a broader scope, such as the view scope.


Update as to your update, you're binding the selected values of all checkboxgroups to one and same bean property #{cartBean.selectedExtras}. This way every iteration overrides the property with the values from the current iteration round as long as until you end up with the values of the last iteration. If you've placed a debug breakpoint on the setter, you'd have noticed that.

This is not right. They should each point to a different bean property. Technically, you should have a #{item.selectedExtras} as property. But I think that this makes no sense in your current design. Better would be to make the #{cartBean.selectedExtras} an List<Item[]> or Item[][]. This way you can get them to set based on the iteration index as follows:

<ui:repeat var="item" value="#{category.items}" varStatus="iteration">
    <p:selectManyCheckbox id="extraCheckbox" value="#{cartBean.selectedExtras[iteration.index]}" layout="pageDirection" converter="omnifaces.SelectItemsConverter">  
         <f:selectItems value="#{item.items5}" var="extra" itemLabel="#{extra.name}"/>
    </p:selectManyCheckbox>
</ui:repeat>

In case of List<Item[]> you only need to make sure that you preinitialize selectedExtras with nulls as many times as there are #{category.items} in bean's (post)constructor.

for (Item item : category.getItems()) {
    selectedExtras.add(null);
}

In case of Item[][], you can suffice with

selectedExtras = new Item[category.getItems().size()];
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for your efforts. Probably I really did post to little code. Actually the `#{item}` in this case is a variable from a higher `` - there do not seem to be any scope related issues. And I noticed, that the problem is not really about many checkboxes but just about my first two entries having checkboxes: The setter methods just aren't called on the first two entries. The other (also) ``-created entries and their checkboxes work fine (setter methods called). – Lester Oct 31 '12 at 08:02
  • Hmm... it's not the first two ``-created entries for which the setter not called: It's only the last entry for which the setter method is called. That's a hint... but I still didn't find the problem. – Lester Oct 31 '12 at 08:41
  • I edited my question. I'm really sorry for requiring your time without providing enough information. I was not clear about the context of the problem and I am always worried to post masses of unrelated code. – Lester Oct 31 '12 at 09:32
  • In the future, you'd better try to create a blank view with a blank bean and then fill up the `` with the smallest possible code which demonstrates/reproduces the whole problem at its own in such way that others should be able to do the same by just copypasting it into their environment. Then, copy the entire `` content into your question. – BalusC Oct 31 '12 at 12:05
  • Wow, this still gives me a hard time. Before I had a `` instead of each Checkbox and it worked with the property `#{cartBean.selectedExtras}` for all of them. No doubt it is just like you say, but still instead of really getting the difference to my previous approach I just get a headache. Would you mind pointing out that difference to me? I'm still struggling implementing your approach. A List of a List just on backing bean side I had once before, but I am absolutely not familiar with the EL on JSF side. Hint on more info? :D – Lester Oct 31 '12 at 16:07
  • The updated answer also contains a concrete example of the view side with changed attributes and EL and so on. As to why it worked with command link, I have no idea what you mean, but multiple command links can without trouble share the one and same method. It would be invoked only once anyway, not for every single link. – BalusC Oct 31 '12 at 16:08
  • I edited the question again including the struggle with the fixing approach. – Lester Oct 31 '12 at 20:14
  • Right, that didn't work as expected. You really need `List`. The `List>` ain't going to work as generic type information is lost during runtime anyway and it defaults to an object array. I updated the answer. – BalusC Oct 31 '12 at 20:27
  • Ah! Now it's really getting painful. I messed up. Actually it starts with a `List`, each has a `List` and of those each has a `List` and those have further `List`s. The site lives on ``. I'm not sure if this wouldn't grow a monster, if the only way is to use static Arrays... :( – Lester Oct 31 '12 at 23:33
  • In that case, you'd probably better bind the input values to the currently iterated item instead, like as initially suggested in my answer. – BalusC Nov 01 '12 at 00:48
  • Thank you so much for all your efforts! Somehow your proposed way would be quite clean and easy. Anyway I say "quite clean" because I feel `selectedExtras` doesn't really belong there. The Entity `Item` represents a table in the database and it just doesn't feel right for it to have an attribute for temporary, runtime sensitive data. Am I wrong? – Lester Nov 01 '12 at 06:10
  • Okay, no, it wouldn't make sense after all. – BalusC Nov 01 '12 at 10:35
  • Thank you for your continuous help and not abandoning me long ago for all the disturbing mistakes I still make asking questions on this board. I promise improvement. Although my problem might be still unsolved, is this answer to be marked as accepted since it could help people with a quite similar problem? And if you still see any approach how this tricky problem might be solved anyway... ;) – Lester Nov 01 '12 at 12:39
  • What exactly is your concrete problem now? I understood that the technical problem is been solved (i.e.: it works), but that you're now actually sitting with a design problem (i.e.: it's ugly). – BalusC Nov 01 '12 at 12:41
  • You are right, the concrete problem is a design problem: How can I resource efficiently save those Checkboxes and still keep it connected to the Item they belong to? A four dimensional array taking up half the database to finally save about four checkboxes seems quite inefficient. Maybe the solution is a new database query for the items of a category? That way there would be a break. – Lester Nov 01 '12 at 13:21
  • Technically, Stack Overflow is for technical questions/problems, not for design quesitons/problems ;) You might want to consider creating a view-specific DTO which extends from `Item` and adds a new property. – BalusC Nov 01 '12 at 13:24
  • Sorry, I wasn't aware of that. Thank you too for that last hint. :) – Lester Nov 02 '12 at 07:48