Ced
Ced

Reputation: 17337

dynamic number of selectonemenu

I've two pieces of code, one that work and one that doesn't. I'm accessing accessing different objects in from a list in different selectOneMenu. So if my list is of size 4 then I have 4 selectOneMenu. There is a spinner above the selectOneMenu 's to notify how many of them I want. I don't understand why the first one using varstatus to access a list works and the second one which use the var doesn't. A Map is a custom entity btw.

Works :

<p:spinner value="#{matchCreation.numbreOfmaps}" min="1" max="7">
    <f:ajax event="change" render="mapsGroup" execute="mapsGroup"/>
</p:spinner>
<!-- maps start  -->
<h:panelGroup id="mapsGroup">
    <table>
        <ui:repeat var="mapPlayed" value="#{matchCreation.playedMaps}" varStatus="status">
            <tr><td>
                <p:selectOneMenu value="#{matchCreation.playedMaps[status.index]}">
                    <f:selectItems value="#{matchCreation.mapList}" var="map" itemValue="#{map}" itemLabel="#{map.name}"/>
                    <f:converter binding="#{mapConverter}"/>
                </p:selectOneMenu>
            </td></tr>  
        </ui:repeat> 
    </table>
</h:panelGroup>

Does NOT work :

<p:spinner value="#{matchCreation.numbreOfmaps}" min="1" max="7">
    <f:ajax event="change" render="mapsGroup" execute="mapsGroup"/>
</p:spinner>
<!-- maps start  -->
<h:panelGroup id="mapsGroup">
    <table>
        <ui:repeat var="mapPlayed" value="#{matchCreation.playedMaps}">
            <tr><td>
                <p:selectOneMenu value="#{mapPlayed}">
                    <f:selectItems value="#{matchCreation.mapList}" var="map" itemValue="#{map}" itemLabel="#{map.name}"/>
                    <f:converter binding="#{mapConverter}"/>
                </p:selectOneMenu>
            </td></tr>  
        </ui:repeat> 
    </table>
</h:panelGroup>

In this one the list will contain the number of map specified but they will all be equal to mapList.get(0).

java:

private List<Map> mapList; // initiated in post construct.
private List<Map> playedMaps;
private int numbreOfmaps = 1;

public List<Map> getPlayedMaps() {
    // I know this is not advised but I didn't really think of another way.
    // It's not heavy work anyway.
    while (playedMaps.size() > numbreOfmaps) {
        playedMaps.remove(playedMaps.size() - 1);
    }
    while (playedMaps.size() < numbreOfmaps) {
        playedMaps.add(mapList.get(0));
    }
    return playedMaps;
}

Upvotes: 0

Views: 1114

Answers (1)

BalusC
BalusC

Reputation: 1108742

<ui:repeat var="mapPlayed"> represents a scoped variable, not a bean property. To imagine the "under the covers" working, it look like:

for (Map mapPlayed : matchCreation.getPlayedMaps()) {
    // ...
    System.out.println(mapPlayed);
}

When using <p:selectOneMenu value="#{mapPlayed}">, JSF actually sets the submitted value in the scoped variable, not the bean property. Under the covers, imagine it like:

for (Map mapPlayed : matchCreation.getPlayedMaps()) {
    Map newMapPlayed = getSubmittedValueSomehow();
    mapPlayed = newMapPlayed;
    // ...
}

This doesn't get reflected in the list.

With the loop index it works better:

for (int index = 0; index < matchCreation.getPlayedMaps().size(); index++) 
    Map newMapPlayed = getSubmittedValueSomehow();
    matchCreation.getPlayedMaps().set(index, newMapPlayed);
    // ...
}

Unrelated to the concrete problem, shadowing names of standard Java SE API classes like Map (from java.util.Map) is a terribly bad idea.

Upvotes: 1

Related Questions