I'm trying to refresh state of boolean variable every time user change selected value from h:selectManyCheckbox. I have survey that loads dynamicly from DB. There are two types of questions multiple choice and single choice. When one of the answers to question have boolean value (additional answer is required), after selecting this option inputText should appear. I have succeed in creating this solution for single choice questions and SelectOneRadio and it works as I wanted.
Unfortunately it doesn't work for SelectManyCheckbox. When I put <f:ajax>
tag into <f:selectItems ... >
it throw error:
ERROR:
javax.servlet.ServletException: <f:ajax> contains an unknown id 'podgladAnkietyForm:repeatLoop:2:selectBoxes' - cannot locate it in the context of the component selectBoxes
I think it is some kind of problem with <ui:repeat>
. When I try execute similar code with selectManyBox but outside ui:repeat loop it works. Moreover almost same code work with <h:selectOneRadio>
!
I tried binding component that I want to refresh, changing absolute path render=":podgladAnkietyForm:repeatLoop:#{loop.index}:selectBoxes"
, adding additional NamingContainer <f:subView>
but it also didn't help.
When I remove <f:ajax>
tag it work. Result code is:
Result html code
<input name="podgladAnkietyForm:repeatLoop:3:selectBoxes" id="podgladAnkietyForm:repeatLoop:3:selectBoxes:0" value="121" type="checkbox"><label for="podgladAnkietyForm:repeatLoop:3:selectBoxes:0" class=""> Answer content</label>
I don't have any clue what I might done wrong. Has anyone had similar problem? I can't remove ui:repeat loop because it loads all questions from DB. Some work-around?
JSF Page
<h:form id="podgladAnkietyForm" prependId="true" >
<ui:repeat value="#{fillSurvey.surveyQuestions}" var="surveyQuestion" varStatus="loop" id="repeatLoop">
<br/>
<h:outputText value=" Pytanie #{loop.index + 1}" styleClass="naglowek" style="font-size: medium;" />
<h:outputText value=" * odpowiedź obowiązkowa " rendered="#{surveyQuestion.question.isMandatory}" style="color: red; font: small bold"/><br/>
<h:outputText value="#{surveyQuestion.question.content}" /> <br/>
<h:panelGroup rendered="#{surveyQuestion.question.isMultiplechoice}" id="multiplechoiceGroup" >
<h:selectManyCheckbox value="#{surveyQuestion.answers}" id="selectBoxes" layout="pageDirection" required="#{surveyQuestion.question.isMandatory}">
<f:selectItems value="#{surveyQuestion.optionsList}" var="entry" itemLabel="#{entry.content}" itemValue="#{entry.optionId}" id="multiplechoiceOption" />
<f:ajax />
<f:ajax event="click" execute="@this" listener="#{surveyQuestion.checkSelected}" render="selectBoxes" />
</h:selectManyCheckbox>
<h:inputText label="Pytanie #{loop.index + 1}" value="#{surveyQuestion.descriptionValue}" style="display: block;" rendered="#{surveyQuestion.haveDesc}" required="#{surveyQuestion.needDesc}" id="textField" />
</h:panelGroup>
<!-- This part of code works perfectly - SelectOneRadio - After selecting option that require additional description TextInput is showed -->
<h:panelGroup rendered="#{!surveyQuestion.question.isMultiplechoice}" id="selectOneGroup" >
<h:selectOneRadio value="#{surveyQuestion.selectedItem}" id="selectOneID" layout="pageDirection">
<f:selectItems value="#{surveyQuestion.optionsList}" var="entry" itemLabel="#{entry.content}" itemValue="#{entry.optionId}" id="OneSelectOption" />
<f:ajax event="click" execute="@this" render="selectOneGroup" listener="#{surveyQuestion.counter}" />
</h:selectOneRadio>
<h:inputText label="Pytanie #{loop.index + 1}" value="#{surveyQuestion.descriptionValue}" style="display: block;" rendered="#{surveyQuestion.haveDesc}" required="#{surveyQuestion.needDesc}" size="40"/>
<h:outputText value="#{surveyQuestion.testField}" />
</h:panelGroup>
</ui:repeat>
<br/><br/>
<h:commandButton action="#{fillSurvey.validateSurvey()}" value="Validate" /> <br/>
</h:form>
Backing Bean
public class SurveyQuestion implements Serializable {
Question question;
List<Options> optionsList;
List<String> answers;
boolean haveDesc;
boolean needDesc;
int selectedItem;
String descriptionValue;
int testField;
///Getters and setters
public void counter(AjaxBehaviorEvent e){
for(Options opt: optionsList){
if ( selectedItem == opt.getOptionId()) {
if(opt.getHaveDesc() || opt.getDescReqr()){
this.haveDesc = true;
if (opt.getDescReqr()) {
this.needDesc = true;
} else {
this.needDesc = false;
}
} else {this.haveDesc = false; this.needDesc=false; }
}
}
testField++;
}
//its empty but it will look like the one above
public void checkSelected(AjaxBehaviorEvent e){
testField++;
}
}