The FacesContext#getViewRoot()
returns the JSF component tree. This is exactly the same tree as represented by XHTML source code after thinking away all taghandlers (JSTL, <ui:include>
, etc). You need to realize that there's only one <h:selectBooleanCheckbox id="checkbox">
in there. It's available in UIViewRoot#findComponent()
by exactly that ID "form:rm:checkbox"
.
It's just its HTML representation which get regenerated multiple times depending on the current iteration round of the parent <h:dataTable>
. This generated HTML representation has in turn client IDs with the current row index inlined. This HTML representation is obviously not available in the component tree.
The component's state (the submitted values, etc), is also only available during iterating the <h:dataTable>
and not before or after. Essentially, you're trying to access the value of the component in bean's action method while the <h:dataTable>
component isn't iterating over it, so the values will always return null
.
In order to programmatically simulate a <h:dataTable>
iteration so that you can collect the desired values, you need to visit the <h:dataTable>
by UIComponent#visitTree()
and collect the information of interest in the VisitCallback
implementation.
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;
}
});
However, you're going in completely the wrong direction as to solving the concrete problem. You should be performing the validation in a validator associated with the input component you'd like to validate, not in the action method. Here's how you could solve the particular concrete functional requirement of validating the input field as required
only when the checkbox in the same row is checked:
<h:column>
<h:selectBooleanCheckbox binding="#{checkbox}" ... />
</h:column>
<h:column>
<h:inputText ... required="#{checkbox.value}" />
</h:column>
That's all. Additional advantage is, the validators run while the <h:dataTable>
is iterating, so you don't need all that visitTree()
code as well.