我正在 JSF 2 中编写验证器方法。我有一个 ui:repeat
我的页面中呈现项目列表的元素。每个项目都有一个日期属性,我需要确保日期以特定的顺序相互对应,例如列表中最后一项的日期不早于第一项的日期。我试图获取 ui:repeat 中的所有子元素并迭代它们以进行比较,但我真的不知道从哪里开始。我已经看到如何通过 ID 获取特定元素:
UIInput input = (UIInput) context.getViewRoot().findComponent(elementId);
然而,在
ui:repeat
内JSF 使 ID 值唯一,所以我不知道它们在编译时是什么。此外,在编译时我不知道列表中有多少项。我已经查看了
UIViewRoot
的 Javadoc和其他相关的类,并尝试了一些东西,但我遇到了错误,东西不起作用,我真的不知道我是否接近到达任何地方。我将我的尝试代码从这篇文章中删除,因为它们可能是一个笑话。
最佳答案
物理上只有 一 UIInput
其状态根据 UIRepeat
的当前迭代轮变化而变化的组件.它仅通过其客户端 ID 可用,无需 UIRepeat
索引:findComponent("formId:inputId")
(UIRepeat
索引仅在客户端有意义)。但是,当组件以编程方式在 UIRepeat
的上下文之外被访问时这样,那么它确实会返回一个看似空的状态。
为了访问UIInput
所有这些状态的组件,因为它们在 UIRepeat
中并收集它们的值,您需要运行 UIComponent#visitTree()
在 UIRepeat
.
这是一个启动示例:
<ui:repeat value="#{bean.items}" var="item">
<f:event type="postValidate" listener="#{bean.validateOrder}" />
<h:inputText value="#{item.value}" />
</ui:repeat>
有了这个
validateOrder()
方法(同样,只是一个启动示例,这种方法天真地假设中继器中只有一个 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!"));
}
}
请注意,它访问了树两次;第一次收集值,第二次将这些输入标记为无效。另请注意,使用标准 JSF 验证器无法完成此非常具体的要求。您不能附加
<f:validator>
在 <ui:repeat>
.贴在 <h:inputText>
理论上是可能的,但它会导致相同的验证器运行与重复项目数量一样多的次数,这是没有意义的。此外,验证器需要接受 getSubmittedValue()
对比 getValue()
考虑到这种方式。OmniFaces 有一个
<o:validateOrder>
组件在固定组件上做类似的事情,但它不是为在动态重复的组件中使用而设计的。
关于validation - 验证 ui :repeat 中项目的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18469551/