Доступ к динамическим компонентам UIC в JSF Managed Bean

У меня есть страница JSF, в которой я перебираю список в <h:dataTable> отобразить несколько строк, содержащих флажок, текст и текстовое поле.

Я должен подтвердить <h:dataTable> так что когда пользователь проверяет флажок, он должен ввести некоторый текст внутри текстового поля.

Это моя страница JSF.

 <h:form prependId="false" id="form">
    <h:dataTable id="rm" width="100%" cellspacing="4"
    value="#{controller.alertTriggers}" var="alt"
        columnClasses="c1,c2,c3,c4">                    


            <h:column>
              <h:selectBooleanCheckbox value="#{alt.checkValue}" id="checkbox"/>
           </h:column>
            <h:column>
               <h:outputText value="#{alt.id}" />                                       
            </h:column>
            <h:column>
              <h:outputFormat value="#{alt.msg1}" />                              
            </h:column>
            <h:column>                                              
                 <h:message for="emailID" id="email" styleClass="validation-error"/>
                 <h:inputText value="#{alt.mailId}" id="emailID" style="width: 87%;" />

            </h:column>                                         

    </h:dataTable>                                          
</h:form>                                       

Я дал идентификатор всех флажков как checkbox и идентификатор всех текстовых полей как emailID, Когда страница отрисована, при проверке источника страницы я обнаружил, что идентификаторы флажков - "rm:0:checkbox", "rm:1:checkbox"... и идентификаторы текстовых полей - "rm: 0: EMAILID", 'тт: 1: EMAILID'..

В контроллере я хочу получить доступ к этим динамическим текстовым полям и флажкам, для которых я использую следующий код:

 FacesContext context = FacesContext. getCurrentInstance();


                  for (int i=0;i<9;i++){
                       UIInput u=(UIInput) FacesContext.getCurrentInstance().getViewRoot().findComponent( "form:rm:" +i+":checkbox" );
                        if ((Boolean) u.getValue()){
                              UIInput ui=(UIInput) FacesContext.getCurrentInstance().getViewRoot().findComponent( "form:rm:" +i+":emailID" );

                               //code

                       }
                 }

Но это дает java.lang.NullPointerException

Даже используя код:

  UIInput u=(UIInput) FacesContext.getCurrentInstance().getViewRoot().
   findComponent( "form:rm:0:checkbox" ); gives the same exception.

Но если я использую

     UIInput u=(UIInput) FacesContext.getCurrentInstance().getViewRoot().
       findComponent( "form:rm:checkbox" );

это не дает исключение нулевого указателя, но я не знаю, какое значение этого флажка дает.

Итак, в итоге,

JSF генерирует идентификаторы как rm:1:checkbox,rm:2:checkbox и т. Д., Но когда я пытаюсь получить доступ к этому компоненту пользовательского интерфейса на странице JSF, я не могу это сделать.

Я что-то пропустил?

1 ответ

Решение

FacesContext#getViewRoot() возвращает дерево компонентов JSF. Это то же самое дерево, которое представлено исходным кодом XHTML после обдумывания всех обработчиков тегов (JSTL, <ui:include>, так далее). Вы должны понимать, что есть только один <h:selectBooleanCheckbox id="checkbox"> там. Это доступно в UIViewRoot#findComponent() именно по этому идентификатору "form:rm:checkbox",

Это просто его HTML-представление, которое генерируется несколько раз в зависимости от текущего цикла итерации родительского элемента. <h:dataTable>, Это сгенерированное представление HTML в свою очередь имеет идентификаторы клиента с текущим индексом строки. Это HTML-представление, очевидно, недоступно в дереве компонентов.

Состояние компонента (представленные значения и т. Д.) Также доступно только во время итерации <h:dataTable> а не до или после. По сути, вы пытаетесь получить доступ к значению компонента в методе действия bean-компонента, пока <h:dataTable> компонент не перебирает его, поэтому значения всегда будут возвращаться null,

Для того, чтобы программно моделировать <h:dataTable> итерации, так что вы можете собрать нужные значения, вам нужно посетить <h:dataTable> от UIComponent#visitTree() и собирать информацию, представляющую интерес в VisitCallback реализация.

UIData table = (UIData) viewRoot.findComponent("form:rm");
table.visitTree(VisitContext.createVisitContext(FacesContext.getCurrentInstance()), new VisitCallback() {
    @Override
    public VisitResult visit(VisitContext context, UIComponent target) {
        if (target instanceof HtmlSelectBooleanCheckbox) {
            HtmlSelectBooleanCheckbox checkbox = (HtmlSelectBooleanCheckbox) target;
            System.out.println("id: " + checkbox.getId());
            System.out.println("value: " + checkbox.getValue());
            // Collect them in an arraylist orso.
        }

        return VisitResult.ACCEPT;
    }
});

Однако вы идете в совершенно неверном направлении в отношении решения конкретной проблемы. Вы должны выполнять проверку в валидаторе, связанном с компонентом ввода, который вы хотите проверить, а не в методе действия. Вот как вы можете решить конкретное функциональное требование проверки поля ввода как required только когда установлен флажок в той же строке:

<h:column>
    <h:selectBooleanCheckbox binding="#{checkbox}" ... />
</h:column>
<h:column>                                              
    <h:inputText ... required="#{checkbox.value}" />
</h:column>

Это все. Дополнительным преимуществом является то, что валидаторы работают, пока <h:dataTable> повторяется, так что вам не нужно все это visitTree() код также.

Другие вопросы по тегам