Validate if list in <ui:repeat><h:inputText> has at least one non-empty/null value

蓝咒 提交于 2019-12-06 15:05:29
BalusC

This isn't easily possible with a custom validator. There's namely physically only one input component whose state changes with every iteration round. Your best bet is to hook on postValidate event of <ui:repeat> and then visit its children via UIComponent#visitTree() on the UIRepeat.

Here's a kickoff example:

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

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

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!"));
    }
}

Note that it visits the tree twice; first time to collect the values and second time to mark those inputs invalid.

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

See also:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!