我有一个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组件时,我无法执行此操作。
我错过了什么吗?
答案 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()
代码。