问题
I've a List<String>
in my model:
private List<String> list;
// Add to list: "d","e","f","a","u","l","t"
// Getter.
I'm presenting it in the view as below:
<ui:repeat value="#{bean.list}" varStatus="loop">
<h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>
This works fine. Now I'd like to validate if the list contains at least one non-empty/null item. How can I create a custom validator for this?
回答1:
This isn't easily possible with a custom validator. There's namely physically only one input component whose state changes with every iteration round. Your best bet is to hook on postValidate
event of <ui:repeat>
and then visit its children via UIComponent#visitTree() on the UIRepeat
.
Here's a kickoff example:
<ui:repeat value="#{bean.list}" varStatus="loop">
<f:event type="postValidate" listener="#{bean.validateOneOrMore}" />
<h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>
With this validateOneOrMore()
method (again, just a kickoff example, this approach naively assumes that there's only one UIInput
component in the repeater):
public void validateOneOrMore(ComponentSystemEvent event) {
final FacesContext context = FacesContext.getCurrentInstance();
final List<String> values = new ArrayList<>();
event.getComponent().visitTree(VisitContext.createVisitContext(context), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target instanceof UIInput) {
values.add((String) ((UIInput) target).getValue());
}
return VisitResult.ACCEPT;
}
});
values.removeAll(Arrays.asList(null, ""));
if (values.isEmpty()) {
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("Please fill out at least one!"));
}
}
Note that it visits the tree twice; first time to collect the values and second time to mark those inputs invalid.
OmniFaces has an <o:validateOneOrMore> component which does a similar thing on fixed components, but it isn't designed for usage in dynamically repeated components.
See also:
- Validate order of items inside ui:repeat
- OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable
来源:https://stackoverflow.com/questions/28026625/validate-if-list-in-uirepeathinputtext-has-at-least-one-non-empty-null-val