验证<ui:repeat> <h:inputtext>中的列表是否至少有一个非空/空值</h:inputtext> </ui:repeat>

时间:2015-01-19 14:15:13

标签: list jsf validation uirepeat

我的模型中有List<String>

private List<String> list;

// Add to list: "d","e","f","a","u","l","t"
// Getter.

我将在视图中呈现如下:

<ui:repeat value="#{bean.list}" varStatus="loop">
    <h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>

这很好用。现在我想验证列表是否包含至少一个非空/空项。如何为此创建自定义验证器?

1 个答案:

答案 0 :(得分:4)

使用自定义验证器并不容易。它们实际上只是一个输入组件,其状态随着每次迭代轮次而变化。您最好的选择是postValidate事件<ui:repeat>,然后通过UIRepeat上的UIComponent#visitTree()访问其子女。

这是一个启动示例:

<ui:repeat value="#{bean.list}" varStatus="loop">
    <f:event type="postValidate" listener="#{bean.validateOneOrMore}" />
    <h:inputText value="#{bean.list[loop.index]}"/>
</ui:repeat>

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

public void validateOneOrMore(ComponentSystemEvent event) {
    final FacesContext context = FacesContext.getCurrentInstance();
    final List<String> values = new ArrayList<>();

    event.getComponent().visitTree(VisitContext.createVisitContext(context), new VisitCallback() {
        @Override
        public VisitResult visit(VisitContext context, UIComponent target) {
            if (target instanceof UIInput) {
                values.add((String) ((UIInput) target).getValue());
            }
            return VisitResult.ACCEPT;
        }
    });

    values.removeAll(Arrays.asList(null, ""));

    if (values.isEmpty()) {
        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("Please fill out at least one!"));
    }
}

请注意,它访问树两次;第一次收集值,第二次标记这些输入无效。

OmniFaces有一个<o:validateOneOrMore>组件,它在固定组件上做类似的事情,但它不是为动态重复组件的使用而设计的。

另见: