验证 ui:repeat 中项目的顺序 [英] Validate order of items inside ui:repeat

查看:36
本文介绍了验证 ui:repeat 中项目的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 JSF 2 中编写验证器方法.我的页面中有一个 ui:repeat 元素,用于呈现项目列表.每个项目都有一个日期属性,我需要确保日期以特定的顺序相互对应,例如列表中最后一项的日期不早于第一项的日期.我试图获取 ui:repeat 中的所有子元素并迭代它们以进行比较,但我真的不知道从哪里开始.我已经看到如何通过 ID 获取特定元素:

I'm writing a validator method in JSF 2. I have a ui:repeat element in my page that renders a list of items. Each item has a date property, and I need to ensure the dates correspond to each other in a specific sequence, e.g. the date of the last item in the list doesn't come before the date of the first item. I was trying to get all the child elements inside the ui:repeat and iterate over them to do the comparison, but I don't really know where to start. I've seen how to get a specific element by ID:

UIInput input = (UIInput) context.getViewRoot().findComponent(elementId);

但是,在 ui:repeat 中,ID 值由 JSF 设置为唯一的,所以我不知道它们在编译时是什么.此外,在编译时我不知道列表中有多少项.

However, within the ui:repeat the ID values are made unique by JSF, so I don't know what they are at compile time. Furthermore, at compile time I don't know how many items there will be in the list.

我查看了 UIViewRoot 和其他相关类的 Javadoc,并尝试了一些方法,但我遇到了错误,事情不起作用,我真的没有知道我是否接近到达任何地方.我将我的尝试代码从这篇文章中删除,因为它们可能是一个笑话.

I've looked at the Javadoc for UIViewRoot and other associated classes, and have tried a couple things, but I'm getting errors, things aren't working, and I don't really know if I'm even close to getting anywhere. I'm leaving the code of my attempts out of this post, becuase they're probably a joke.

推荐答案

物理上只有一个 UIInput 组件,其状态会根据 的当前迭代轮次而变化UI重复.它仅通过其客户端 ID 可用,没有 UIRepeat 索引:findComponent("formId:inputId")(UIRepeat 索引仅在客户端).但是,当以这种方式在 UIRepeat 的上下文之外以编程方式访问组件时,它确实会返回一个看似空的状态.

There's physically only one UIInput component whose state changes depending on the current iteration round of UIRepeat. It's available by just its client ID without the UIRepeat index: findComponent("formId:inputId") (the UIRepeat index is only of significance in the client side). However, when the component is programmatically been accessed outside the context of UIRepeat this way, then it'll indeed return a seemingly empty state.

为了在 UIRepeat 中访问所有这些状态中的 UIInput 组件并收集它们的值,您需要运行 UIComponent#visitTree()UIRepeat 上.

In order to visit the UIInput component in all those states as they are inside the UIRepeat and collect their values, you need to run UIComponent#visitTree() on the UIRepeat.

这是一个启动示例:

<ui:repeat value="#{bean.items}" var="item">
    <f:event type="postValidate" listener="#{bean.validateOrder}" />
    <h:inputText value="#{item.value}" />
</ui:repeat>

使用这个 validateOrder() 方法(同样,只是一个启动示例,这种方法天真地假设转发器中只有一个 UIInput 组件):

With this validateOrder() method (again, just a kickoff example, this approach naively assumes that there's only one UIInput component in the repeater):

@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 验证器无法完成此非常具体的要求.您不能在 上附加 .将它附加到 理论上是可能的,但它会导致相同的验证器运行的次数与重复项的数量一样多,这是没有意义的.此外,验证器需要以这种方式将 getSubmittedValue()getValue() 考虑在内.

Note that it visits the tree twice; first time to collect the values and second time to mark those inputs invalid. Also note that this very specific requirement can't be done with a standard JSF validator. You can't attach a <f:validator> on <ui:repeat>. Attaching it on <h:inputText> is theoretically possible, but it would cause the very same validator to run as many times as the amount of repeated items, which doens't make sense. Also, the validator would need to take getSubmittedValue() vs getValue() into account this way.

OmniFaces 有一个 组件在固定组件上做类似的事情,但它不是为在动态重复的组件中使用而设计的.

OmniFaces has an <o:validateOrder> component which does a similar thing on fixed components, but it isn't designed for usage in dynamically repeated components.

这篇关于验证 ui:repeat 中项目的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆