验证< ui:repeat>< h:inputText>中的列表是否具有至少一个非空/空值
我的模型中有一个List<String>
:
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?
使用自定义验证程序很难做到这一点.也就是说,实际上只有一个输入组件,其状态会在每一轮迭代中发生变化.最好的选择是挂接<ui:repeat>
的postValidate
事件,然后通过
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
.
这是一个开球示例:
<ui:repeat value="#{bean.list}" varStatus="loop">
<f:event type="postValidate" listener="#{bean.validateOneOrMore}" />
<h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>
使用这种validateOneOrMore()
方法(同样,只是一个启动示例,该方法天真地假设转发器中只有一个UIInput
组件):
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具有 <o:validateOneOrMore>
组件,它在固定组件上做类似的事情,但是它不是为在动态重复的组件中使用而设计的.
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.
- Validate order of items inside ui:repeat
- OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable