在JSF Managed Bean中访问动态UIComponent

时间:2013-09-02 12:21:34

标签: jsf-2 validation uicomponents

我有一个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'...而文本框的那些是'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:复选框等,但是当我尝试在JSF页面中访问此UI组件时,我无法执行此操作。

我错过了什么吗?

1 个答案:

答案 0 :(得分:3)

FacesContext#getViewRoot()返回JSF组件树。在完全考虑所有taghandlers(JSTL,<ui:include>等)之后,这与XHTML源代码所表示的树完全相同。你需要意识到那里只有只有一个 <h:selectBooleanCheckbox id="checkbox">。它仅在UIViewRoot#findComponent()中以ID "form:rm:checkbox"提供。

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

组件的状态(提交的值等)也仅在>迭代<h:dataTable>期间时可用,而不是在之前或之后。从本质上讲,当<h:dataTable>组件没有迭代它时,你试图访问bean的action方法中组件的值,因此值总是会返回null

为了以编程方式模拟<h:dataTable>次迭代以便您可以收集所需的值,您需要访问<h:dataTable> UIComponent#visitTree()并收集VisitCallback中感兴趣的信息。 1}}实施。

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()代码。