1

I`m developing a JSF application and I have a question regarding a Facelets page with JSTL. I want to display in an ui:repeat a number of question, a question and 3 answers (formated conditionally) and in front of the answers a tick (tickSmall.png) or an X (xSmall.png) if the questions are right or wrong.

The answers are formated correctly, but the tick / X is not put correctly (I checked the booleans are correct, some are true, some are false). EVERY time it puts an X, even if there should be a tick.

I have included xmlns:c="http://java.sun.com/jsp/jstl/core

The code:

     <ui:repeat var="n"
                    value="#{answerResultBean.accessWrongAnswerColumnWrapperList}">
                    <hr />
                    <h:outputText value="#{n.noQuestion}. #{n.question}" />
                    <h:panelGrid columns="2" style="text-align: left;">
                        <c:choose>
                            <c:when test="#{n.rightGridAnswerA}">
                                <h:form>
                                    <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
                                </h:form>
                            </c:when>
                            <c:otherwise>
                                <h:form>
                                    <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
                                </h:form>
                            </c:otherwise>
                        </c:choose>
                        <h:outputText value="a) #{n.a}"
                            style="#{n.userAnswerA ? 'font-weight:bold;' : 'font-weight:normal;'}" />

                        <c:choose>
                            <c:when test="#{n.rightGridAnswerB}">
                                <h:form>
                                    <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
                                </h:form>
                            </c:when>
                            <c:otherwise>
                                <h:form>
                                    <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
                                </h:form>
                            </c:otherwise>
                        </c:choose>
                        <h:outputText value="b) #{n.b}"
                            style="#{n.userAnswerB ? 'font-weight:bold;' : 'font-weight:normal;'}" />

                        <c:choose>
                            <c:when test="#{n.rightGridAnswerC}">
                                <h:form>
                                    <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
                                </h:form>
                            </c:when>
                            <c:otherwise>
                                <h:form>
                                    <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
                                </h:form>
                            </c:otherwise>
                        </c:choose>
                        <h:outputText value="c) #{n.c}"
                            style="#{n.userAnswerC ? 'font-weight:bold;' : 'font-weight:normal;'}" />
                    </h:panelGrid>
                </ui:repeat>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
CyberGriZzly
  • 379
  • 3
  • 9
  • 22

1 Answers1

3

JSTL tags and JSF components doesn't run in sync as you'd expect from the coding. JSTL tags runs first during view build time, producing the JSF component tree. JSF components runs thereafter during view render time, producing HTML output. So, when JSTL runs, the #{n} is nowhere available in the EL scope, because the <ui:repeat> hasn't run at that moment.

You need JSF component's rendered attribute instead, or make use of the ternary operator in EL the smart way.

The following blocks of clumsiness

<c:choose>
    <c:when test="#{n.rightGridAnswerA}">
        <h:form>
            <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
        </h:form>
    </c:when>
    <c:otherwise>
        <h:form>
            <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
        </h:form>
    </c:otherwise>
</c:choose>
...
<c:choose>
    <c:when test="#{n.rightGridAnswerB}">
        <h:form>
            <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
        </h:form>
    </c:when>
    <c:otherwise>
        <h:form>
            <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
        </h:form>
    </c:otherwise>
</c:choose>
...
<c:choose>
    <c:when test="#{n.rightGridAnswerC}">
        <h:form>
            <img src="/juritest/resources/img/tickSmall.png" alt="tick" />
        </h:form>
    </c:when>
    <c:otherwise>
        <h:form>
            <img src="/juritest/resources/img/xSmall.png" alt="wrong" />
        </h:form>
    </c:otherwise>
</c:choose>

can be rewritten as follows using the rendered attribute:

<h:form>
    <h:graphicImage name="img/tickSmall.png" alt="tick" rendered="#{n.rightGridAnswerA}" />
    <h:graphicImage name="img/xSmall.png" alt="wrong" rendered="#{not n.rightGridAnswerA}" />
</h:form>
...
<h:form>
    <h:graphicImage name="img/tickSmall.png" alt="tick" rendered="#{n.rightGridAnswerB}" />
    <h:graphicImage name="img/xSmall.png" alt="wrong" rendered="#{not n.rightGridAnswerB}" />
</h:form>
...
<h:form>
    <h:graphicImage name="img/tickSmall.png" alt="tick" rendered="#{n.rightGridAnswerC}" />
    <h:graphicImage name="img/xSmall.png" alt="wrong" rendered="#{not n.rightGridAnswerC}" />
</h:form>

or as follows using the conditional operator:

<h:form>
    <h:graphicImage name="img/#{n.rightGridAnswerA ? 'tick' : 'x'}Small.png" alt="#{n.rightGridAnswerA ? 'tick' : 'wrong'}" />
</h:form>
...
<h:form>
    <h:graphicImage name="img/#{n.rightGridAnswerB ? 'tick' : 'x'}Small.png" alt="#{n.rightGridAnswerB ? 'tick' : 'wrong'}" />
</h:form>
...
<h:form>
    <h:graphicImage name="img/#{n.rightGridAnswerC ? 'tick' : 'x'}Small.png" alt="#{n.rightGridAnswerC ? 'tick' : 'wrong'}" />
</h:form>

(which is still not DRY, but that's a different problem)

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you BalucC for your answer; I didn't know about the synchronisation problem between JSTL and JSF. I used for example c:choose tag successfully with JSF and I didn't thought it was a problem. (maybe I was lucky :)). – CyberGriZzly Mar 21 '13 at 19:31
  • You're welcome. Please note that it's not exactly a "synchronisation problem" :) The one runs during view build time, the other runs during view render time. That's all. You just have to pick the right tool for the job. – BalusC Mar 21 '13 at 19:33
  • Anther qeustion relating to the issue: what is the best practice to display something conditional? – CyberGriZzly Mar 21 '13 at 23:22