jsfuirepeatselectmanycheckbox

Collection of selectManyCheckbox inside a ui:repeat knows which element of the repeater it belongs to


I am developing a web app using JSF 2. My web app among other things contains a series of questions put one at a time (so one question is visible at a time) and have multiple answers (I use h:selectManyCheckbox).

I store the questions and possible answers in a ArrayList ("gridQuestionListClone") and the users answers (before checking them at the end) in a HashMap ("allQuestionUserAnswerMap"). (I could change the storage modality if the answer demands it).

When the user finishes answering all the questions I want to give the user the possibility to recheck all the questions and answers (I want the answers preloaded) in a page. So all the questions and their corresponding checkboxes (3 at each question) with the users checked checkboxes in one page.

So I use ui:repeat to go through all the questions and possible answers and I need a mechanism to check the right checkboxes (which the user checked) and give the user the possibility to change his/hers answers and when I press a submit button (for example) to know which checkboxes to which questions correspond. A sketch to make things clearer :)) (maybe). So when the user finished answering all the single questions I want to show him:

Question 1:
a) answer1 - CHECKED
b) answer2 - UNCHECKED
c) answer3 - CHECKED
------------------------
Question 2:
a) answer1 - UNCHECKED
b) answer2 - UNCHECKED
c) answer3 - CHECKED
------------------------
Question 3:
a) answer1 - CHECKED
b) answer2 - CHECKED
c) answer3 - UNCHECKED
------------------------
.
.
.
Question n:
a) answer1 - CHECKED
b) answer2 - UNCHECKED
c) answer3 - CHECKED
------------------------ 
SUBMIT button

The user checks his/hers answers and modifies them if needed and presses the submit button. Then I would like to have a collection of some kind (or multiple I don't really care, afterwards I could merge them) which contains the number of the question and the possible answers like in "allQuestionUserAnswerMap" at the begging or something like that.

My trivial code (not correct):

<ui:repeat var="p" value="#{gridPopUpBean.gridQuestionListClone}">
                    <hr />
                    <h:panelGrid columns="2">
      ...
                        <h:panelGroup style="text-align: left">
                            <h:selectManyCheckbox
                                value="#{gridPopUpBean.oneQuestionUserAnswerList}"
                                layout="pageDirection">
                                <f:selectItem itemValue="a"
                                    itemLabel="#{p.a}" />
                                <f:selectItem itemValue="b"
                                    itemLabel="#{p.b}" />
                                <f:selectItem itemValue="c"
                                    itemLabel="#{p.c}" />
                            </h:selectManyCheckbox>
        ...
                        </h:panelGroup>
                    </h:panelGrid>
                </ui:repeat>

Any ideas?


Solution

  • Simplest way would be to just bind the value of the checkbox group to the currently iterated object instead of all checkbox groups to one and same parent bean property.

    In code, just replace

    value="#{gridPopUpBean.oneQuestionUserAnswerList}"
    

    by

    value="#{p.oneQuestionUserAnswerList}"
    

    and make changes in the model accordingly.

    Alternatively, you can also provide a Map of all answers by question ID in the parent bean. Here's a kickoff example which uses more self-documenting variable names than you have, so that it's better understandable:

    <ui:repeat value="#{bean.questions}" var="question">
        ...
        <h:selectManyCheckbox value="#{bean.answers[question.id]}">
            <f:selectItems value="#{question.answers}" />
        </h:selectManyCheckbox>
        ...
    </ui:repeat>
    

    with e.g.

    private Map<Long, Answer[]> answers = new HashMap<Long, Answer[]>();