There, physically, only the component is one UIInput , the state of which changes depending on the current round of iteration of the UIRepeat . It is accessible only by its client identifier without the UIRepeat : findComponent("formId:inputId") index (the UIRepeat index only matters on the client side). However, when a component is programmatically accessible outside the UIRepeat context UIRepeat this way, it does return a seemingly empty state.
To visit the UIInput component in all these states, as they are inside the UIRepeat , and collect their values, you need to run UIComponent#visitTree() on the UIRepeat .
Here is an example run:
<ui:repeat value="#{bean.items}" var="item"> <f:event type="postValidate" listener="#{bean.validateOrder}" /> <h:inputText value="#{item.value}" /> </ui:repeat>
Using this method validateOrder() (again, just an example run, this approach naively assumes that there is only one UIInput component in the UIInput ):
@SuppressWarnings("rawtypes") public void validateOrder(ComponentSystemEvent event) { final FacesContext context = FacesContext.getCurrentInstance(); final List<Comparable> values = new ArrayList<Comparable>(); event.getComponent().visitTree(VisitContext.createVisitContext(context), new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (target instanceof UIInput) { values.add((Comparable) ((UIInput) target).getValue()); } return VisitResult.ACCEPT; } }); boolean ordered = new ArrayList<Comparable>(new TreeSet<Comparable>(values)).equals(values); if (!ordered) { event.getComponent().visitTree(VisitContext.createVisitContext(context), new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (target instanceof UIInput) { ((UIInput) target).setValid(false); } return VisitResult.ACCEPT; } }); context.validationFailed(); context.addMessage(null, new FacesMessage("Values are not in order!")); } }
Notice that he visits the tree twice; the first time to collect values ββand the second time to mark these inputs incorrect. Also note that this very specific requirement cannot be met with the standard JSF validator. You cannot attach <f:validator> to <ui:repeat> . It is theoretically possible to attach it to <h:inputText> , but this will lead to the fact that the same validator will work as many times as the number of repeating elements, which makes no sense. In addition, the validator will have to consider getSubmittedValue() vs getValue() in this way.
OmniFaces has a <o:validateOrder> component that does the same thing on fixed components, but is not intended to be used in dynamically repeating components.
Balusc
source share