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

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

问题描述

我正在JSF 2中编写一个验证器方法.我的页面中有一个ui:repeat元素,用于显示项目列表.每个项目都有一个date属性,我需要确保日期以特定的顺序相互对应,例如列表中最后一项的日期不早于第一项的日期.我试图在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组件,其状态根据UIRepeat的当前迭代周期而变化.仅通过其客户端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.

为了访问处于所有状态的UIInput组件,并收集它们的值,您需要运行

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验证器无法满足这一非常具体的要求.您不能在<ui:repeat>上附加<f:validator>.从理论上讲,可以将其附加到<h:inputText>上,但这将使相同的验证程序运行与重复项的数量一样多的次数,这是没有意义的.此外,验证者还需要以这种方式考虑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有一个 <o:validateOrder> 组件,它在固定组件上做类似的事情,但它不适用于动态重复的组件.

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天全站免登陆