Access dynamic UIComponents in JSF Managed Bean

I have a JSF page in which I repeat the list in <h:dataTable> to display some lines containing a checkbox, text and text box.

I have to check <h:dataTable> so that when the user checks the checkbox, he must enter the text inside the text box.

This is my JSF page.

  <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> 

I specified the identifier of all the flags as checkbox and the id of all text fields as emailID . When the page is displayed, when checking the source of the page, I found that the identifiers of the flags are: "rm: 0: checkbox", "rm: 1: checkbox" ... and those of the text fields: "rm: 0: EMAILID", 'tm: 1: EMAILID '..

In the controller, I want to access these dynamic text fields and check boxes for which I use the following code:

  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 } } 

But this gives java.lang.NullPointerException

Even using the code:

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

But if I use

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

it does not give a Null Pointer Exception, but I do not know if checkbox has a value.

So in general

JSF generates identifiers like rm: 1: checkbox, rm: 2: checkbox, etc., but when I try to access this component of the user interface on the JSF page, I cannot do this.

Am I missing something?

+3
source share
1 answer

FacesContext#getViewRoot() returns the JSF component tree. This is exactly the same tree as represented by the XHTML source code after we skipped all the tag handlers (JSTL, <ui:include> , etc.). You need to understand that there is only one <h:selectBooleanCheckbox id="checkbox"> . It is available in UIViewRoot#findComponent() in the same way as the ID "form:rm:checkbox" .

This is just his HTML representation, which is restored several times depending on the current round of iteration of the parent <h:dataTable> . This generated HTML view, in turn, has client identifiers with the current inlined string index. This HTML view is obviously not available in the component tree.

The component state (represented values, etc.) is also available only during , iteration <h:dataTable> , and not before or after. In essence, you are trying to access the value of the component in the bean action method, while the <h:dataTable> component does not iterate over it, so the values ​​will always return null .

To programmatically simulate an iteration of <h:dataTable> so that you can collect the values ​​you need, you need to visit the <h:dataTable> 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 are going completely in the wrong direction to solve a specific problem. You must perform validation in the validator associated with the input component that you want to validate, and not in the action method. Here you can solve the specific concrete functional requirement of checking the input field as required only when checking the checkbox on the same line:

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

It's all. An added benefit is that validators work while <h:dataTable> , so you don't need all this visitTree() code.

+3
source

Source: https://habr.com/ru/post/982631/


All Articles