3

我有一个 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>                                       

我已将所有复选框的 id 指定为 ,checkbox并将所有文本框的 id 指定为emailID。呈现页面时,在检查页面源时,我发现复选框的 id 是 'rm:0:checkbox','rm:1:checkbox'... 而文本框的 id 是 'rm:0: emailID','rm: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 将 id 生成为 rm:1:checkbox、rm:2:checkbox 等,但是当我尝试在 JSF 页面中访问此 UI 组件时,我无法做到。

我错过了什么吗?

4

1 回答 1

3

FacesContext#getViewRoot()返回 JSF 组件树。在考虑了所有标记处理程序(JSTL <ui:include>,等等)之后,这与 XHTML 源代码所表示的树完全相同。你需要意识到那里只有一个 <h:selectBooleanCheckbox id="checkbox">。它可以UIViewRoot#findComponent()通过该 ID获得"form:rm:checkbox"

它只是它的 HTML 表示,它会根据 parent 的当前迭代轮次重新生成多次<h:dataTable>。这个生成的 HTML 表示又具有内联当前行索引的客户端 ID。这种 HTML 表示显然在组件树中不可用。

组件的状态(提交的值等)也仅迭代期间可用,<h:dataTable>而不是之前或之后。本质上,您是在尝试访问 bean 的 action 方法中组件的值,而<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()代码。

于 2013-09-02T12:51:31.497 回答