我正在JSF 2中编写验证器方法。我的页面中有一个ui:repeat
元素,用于呈现项目列表。每个项目都有一个日期属性,我需要确保日期按特定顺序相互对应,例如列表中最后一项的日期不在第一项的日期之前。我试图获取ui中的所有子元素:重复并迭代它们进行比较,但我真的不知道从哪里开始。我已经看过如何通过ID获取特定元素:
UIInput input = (UIInput) context.getViewRoot().findComponent(elementId);
但是,在ui:repeat
内,JSF使ID值变为唯一,所以我不知道它们在编译时是什么。此外,在编译时我不知道列表中有多少项。
我已经查看了UIViewRoot
和其他相关类的Javadoc,并尝试了几件事,但是我遇到了错误,事情没有用,我真的不知道我是不是甚至接近任何地方。我将离开这篇文章的代码留下来,因为他们可能是个笑话。
答案 0 :(得分:6)
实际上只有一个 UIInput
组件,其状态根据UIRepeat
的当前迭代轮次而变化。它仅由其客户端ID提供,没有UIRepeat
索引:findComponent("formId:inputId")
(UIRepeat
索引仅在客户端具有重要意义)。但是,当以UIRepeat
这种方式以编程方式访问组件时,它确实会返回一个看似空的状态。
要访问UIInput
内所有州的UIRepeat
组件并收集其值,您需要在UIRepeat
上运行UIComponent#visitTree()
。
这是一个启动示例:
<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()
vs getValue()
。
OmniFaces有一个<o:validateOrder>
组件,它在固定组件上做类似的事情,但它不适用于动态重复组件。