Accordion var does not propagate to <c:forEach>

UI Components for JSF
Post Reply
reza_rahman
Posts: 8
Joined: 09 Apr 2012, 18:10

10 Apr 2012, 02:28

I think I have come across a strange bug with the accordion panel that might apply to other PrimeFaces components as well.

It seems that the var defined as part of a dynamic accordion does not propagate to <c:forEach> (the references are always null inside the forEach). Strangely, <ui:repeat> works just fine. Now, I could avoid <c:forEach> as a workaround but it seems like a bit of a hack and a gotcha for the rest of my development team to trip over.

Here is some very simplistic code that demonstrates the problem:

Code: Select all

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:pe="http://primefaces.org/ui/extensions"
    xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>PrimeFaces Accordion/Input Bug</title>
    </h:head>
    <h:body>
        <h:form>
            <p:accordionPanel 
                value="#{tabBean.playerPositions.keySet().toArray()}" 
                var="player"
                multiple="true"
                activeIndex="#{tabBean.activeIndex}"
                dynamic="true">
                <p:tab title="#{player.name}">
                    <h:panelGrid>
                        <h:panelGrid columns="2">
                            <h:outputText value="Name: " />
                            <h:outputText value="#{player.name}"/>

                            <h:outputText value="Number: " />
                            <h:outputText value="#{player.number}"/>

                            <h:outputText value="Position: " />
                            <table>
                                <c:forEach var="position" items="#{tabBean.playerPositions[player]}">
                                    <tr>
                                        <td>
                                            <h:selectBooleanCheckbox value="#{tabBean.positionSelections[position]}" >
                                                <f:ajax event="click" execute="@form" render="@form"  />
                                            </h:selectBooleanCheckbox>
                                        </td>
                                        <td>
                                            <h:outputText value="#{position.name}" />
                                        </td>
                                    </tr>
                                </c:forEach>
                            </table>                            
                        </h:panelGrid>
                    </h:panelGrid>
                </p:tab>
            </p:accordionPanel>
        </h:form>
    </h:body>
</html>

Code: Select all

@Named
@SessionScoped
public class TabBean implements Serializable {

    private Map<Player, Set<Position>> playerPositions;
    private Map<Position, Boolean> positionSelections;

    public TabBean() {
        playerPositions = new HashMap<Player, Set<Position>>();
        positionSelections = new HashMap<Position, Boolean>();

        Player player = new Player("Messi", 10);
        Set positions = new HashSet<Position>();
        Position position = new Position(player.getName(), "Forward");
        positions.add(position);
        positionSelections.put(position, Boolean.TRUE);
        position = new Position(player.getName(), "Midfielder");
        positions.add(position);
        positionSelections.put(position, Boolean.FALSE);
        playerPositions.put(player, positions);


        player = new Player("Iniesta", 8);
        positions = new HashSet<Position>();
        position = new Position(player.getName(), "MidFielder");
        positions.add(position);
        positionSelections.put(position, Boolean.TRUE);
        position = new Position(player.getName(), "Defender");
        positions.add(position);
        positionSelections.put(position, Boolean.TRUE);
        position = new Position(player.getName(), "Sweeper");
        positions.add(position);
        positionSelections.put(position, Boolean.FALSE);
        playerPositions.put(player, positions);

        player = new Player("Villa", 7);
        positions = new HashSet<Position>();
        position = new Position(player.getName(), "Goalkeeper");
        positions.add(position);
        positionSelections.put(position, Boolean.TRUE);
        position = new Position(player.getName(), "Captain");
        positions.add(position);
        positionSelections.put(position, Boolean.TRUE);
        playerPositions.put(player, positions);
    }

    public Map<Player, Set<Position>> getPlayerPositions() {
        return playerPositions;
    }

    public Map<Position, Boolean> getPositionSelections() {
        return positionSelections;
    }
    
    public String getActiveIndex(){
        return "1,2";
    }
}

Code: Select all

public class Player implements Serializable {

    private String name;
    private int number;

    public Player(String name, int number) {
        this.name = name;
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public int getNumber() {
        return number;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Player)) {
            return false;
        }

        return ((Player) obj).getNumber() == this.number;
    }

    @Override
    public int hashCode() {
        int hash = 1;
        return hash * 31 + name.hashCode();
    }

    @Override
    public String toString() {
        return name;
    }
}

Code: Select all

public class Position implements Serializable {

    private String player;
    private String name;

    public Position(String player, String name) {
        this.player = player;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Position other = (Position) obj;
        if ((this.player == null) ? (other.player != null) : !this.player.equals(other.player)) {
            return false;
        }
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 23 * hash + (this.player != null ? this.player.hashCode() : 0);
        hash = 23 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return name;
    }
}
If I am doing something wrong, please advise on the correct way to do this. If this is indeed a bug, please advise on a fix/workaround. Also, let me know if I can provide any further details.

Thanks in advance. I have heard good things about PrimeFaces and this is my first time using it on a project.

PrimeFaces: 3.2
JSF: Mojarra/2.1.0-b11-FCS
Server: GlassFish/3.1.1

arturo
Posts: 90
Joined: 23 Aug 2011, 09:57
Location: Mexico

10 Apr 2012, 04:42

Maybe because c:forEach is a tag handler and they run first, and ui:repeat work because is a real JSF component
PrimeFaces 4.0 | Extensions 1.1.0 | GlassFish 4.0 | Mojarra 2.2.4 | NetBeans 7.3.1

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

10 Apr 2012, 08:09

c:forEach is a taghandler that runs at component tree build time, var is available at render time. Better try ui:repeat as suggested.

Good to see you here Reza, by the way :)

reza_rahman
Posts: 8
Joined: 09 Apr 2012, 18:10

10 Apr 2012, 22:22

OK, thanks for the insight. I'll advise the developers accordingly.

It's good to be here :-). PrimeFaces looks very good so far (despite the couple of relatively minor issues I posted).

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 58 guests