验证 <ui:repeat><h:inputText> 中的列表是否至少有一个 non-empty/null 值
Validate if list in <ui:repeat><h:inputText> has at least one non-empty/null value
我的模型中有一个 List<String>
:
private List<String> list;
// Add to list: "d","e","f","a","u","l","t"
// Getter.
我在下面的视图中展示它:
<ui:repeat value="#{bean.list}" varStatus="loop">
<h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>
这很好用。现在我想验证列表是否包含至少一个 non-empty/null 项。我如何为此创建自定义验证器?
使用自定义验证器不容易做到这一点。也就是说,物理上只有一个输入组件,其状态随每一轮迭代而变化。最好的办法是挂钩 <ui:repeat>
的 postValidate
事件,然后通过 UIRepeat
.
上的 UIComponent#visitTree()
访问其子项
这是一个启动示例:
<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
组件):
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!"));
}
}
注意它访问了树两次;第一次收集值,第二次将这些输入标记为无效。
OmniFaces 有一个 <o:validateOneOrMore>
组件,它在固定组件上做类似的事情,但它不是为在动态重复组件中使用而设计的。
另请参阅:
- Validate order of items inside ui:repeat
- OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable
我的模型中有一个 List<String>
:
private List<String> list;
// Add to list: "d","e","f","a","u","l","t"
// Getter.
我在下面的视图中展示它:
<ui:repeat value="#{bean.list}" varStatus="loop">
<h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>
这很好用。现在我想验证列表是否包含至少一个 non-empty/null 项。我如何为此创建自定义验证器?
使用自定义验证器不容易做到这一点。也就是说,物理上只有一个输入组件,其状态随每一轮迭代而变化。最好的办法是挂钩 <ui:repeat>
的 postValidate
事件,然后通过 UIRepeat
.
UIComponent#visitTree()
访问其子项
这是一个启动示例:
<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
组件):
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!"));
}
}
注意它访问了树两次;第一次收集值,第二次将这些输入标记为无效。
OmniFaces 有一个 <o:validateOneOrMore>
组件,它在固定组件上做类似的事情,但它不是为在动态重复组件中使用而设计的。
另请参阅:
- Validate order of items inside ui:repeat
- OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable