【问题标题】:Validate order of items inside ui:repeat验证 ui:repeat 中项目的顺序
【发布时间】:2013-08-30 10:38:38
【问题描述】:

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

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

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

我查看了 UIViewRoot 和其他相关类的 Javadoc,并尝试了几件事,但我遇到了错误,事情不工作,我真的不知道我是否甚至接近到达任何地方。我将在这篇文章中留下我尝试的代码,因为它们可能是个笑话。

【问题讨论】:

    标签: validation jsf uirepeat


    【解决方案1】:

    物理上只有一个 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 验证器来完成。您不能在&lt;ui:repeat&gt; 上附加&lt;f:validator&gt;。将它附加到&lt;h:inputText&gt; 理论上是可能的,但它会导致同一个验证器运行的次数与重复项的数量一样多,这是没有意义的。此外,验证器需要以这种方式考虑 getSubmittedValue()getValue()

    OmniFaces 有一个 &lt;o:validateOrder&gt; 组件,它在固定组件上做类似的事情,但它不是为在动态重复组件中使用而设计的。

    【讨论】:

    • 此验证发生在 JSF postvalidate 阶段,可能会产生一些副作用。但是,对我来说,它似乎有效。
    • @sinned:应该没有副作用,除非对生命周期有误解。
    • 嗨@BalusC,似乎h:inputText 中的f:attribute 不可用?!知道为什么吗?非常感谢。
    猜你喜欢
    • 2017-08-10
    • 2010-10-23
    • 2011-06-07
    • 1970-01-01
    • 2016-01-18
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    相关资源
    最近更新 更多