3

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++;
}
}
Onizuka
  • 61
  • 1
  • 4
  • 1
    +1 for being well explained ;-) Did you give a try to `render="@this"`? – Aritz Sep 26 '13 at 10:31
  • I tried it again but it didn't solve my problem. As far as I know adding component that implements UI:NamingContainer such as `` should add prefix in the html output :X:someId:Y... In my case `h:panelGroup id="multiplechoiceGroup"' should add prefix multiplechoiceGroup but there is no and i can't refer to that in ajax. In case of single choice question end `SelectOneRadio` in `f:ajax` I refer to panelGroup id and it refresh. – Onizuka Sep 26 '13 at 10:54
  • There are two f:ajax tags, is it a typo? – Johny T Koshy Sep 26 '13 at 11:19
  • Yes my mistake. In code should be only one. Both of version above don't work :) – Onizuka Sep 26 '13 at 11:29

1 Answers1

2

This topic seems to be a little outdated, but anyway...

Your f:ajax element is wrapped inside a ui:repeat element. I had the same situation in my code and what helped me was the answer to this ticket: f:ajax within ui:repeat, unknown id for the component. In short, I had to use the absolute ID of the component being rendered, starting with a colon (:). Hope this helps you, too.

Community
  • 1
  • 1