访问Wicket表单验证器中的任意数量的字段

时间:2012-05-30 15:26:12

标签: java validation wicket

我需要验证类型为TextField<BigDecimal>的几个Wicket输入字段的某些内容(即百分比之和为100)。有一到多个这样的输入字段;事情是,我事先并不知道有多少。

(简化示例)

private class PercentageValidator extends AbstractFormValidator {
    @Override
    public FormComponent<?>[] getDependentFormComponents() {
        // ...
    }

    @Override
    public void validate(Form<?> form) {
        List<TextField<BigDecimal>> fields = // TODO

        // the actual validation where the value of every field is needed
    }
}

ListView的Java代码:

ListView<?> listView = new ListView<PropertyShare>("shares", shares) {
    @Override
    protected void populateItem(ListItem<PropertyShare> item) {
    // ... 
        item.add(new TextField<BigDecimal>("share", ... model ...));
    }
};

HTML:

<tr wicket:id="shares">
   <td> ... </td>
   <td>
     <input wicket:id="share" type="text" size="4"> %
   </td>

</tr>

我尝试将每个TextField保留在页面上的集合中,但这种方法失败,因为封闭populateItem()的{​​{1}}方法不仅被调用,而且首先创建了Page,因此复制字段得到添加到集合中。 (我无法找到一种简单的方法来保持它没有重复。)

使用ListView这一事实似乎也有点使ListView方法中的表单对象中的字段变得复杂。我想我需要使用validate()获取ListView并遍历其子项?

访问form.get("shares")等转发器所包含的任意数量字段的“正确方法”是什么?

3 个答案:

答案 0 :(得分:5)

另一种方法是子类TextField,然后使用Visitor来挑选子类的所有后代组件。

通过这种方式,您可以避免未经检查的转换,并且您不必依赖于ID,这不是一种非常强大的方法。

修改:在实践中,它看起来像这样:

子类:

private static class ShareField extends TextField<BigDecimal> {
   // ...
}

Helper方法,从表单中找到所有ShareField:

private List<ShareField> findShareFields(Form form) {
    final List<ShareField> fields = Lists.newArrayList();
    form.visitChildren(ShareField.class, new IVisitor<ShareField>() {
        @Override
        public Object component(ShareField component) {
            fields.add(component);
            return CONTINUE_TRAVERSAL;
        }
    });
    return fields;
}

答案 1 :(得分:2)

是的,在写这个问题时,我突然意识到,简单地循环遍历form.get("shares")的孩子并获得id为“share”的字段可能会有效。

确实如此。这是一个帮助方法,可以找到“共享”字段:

@SuppressWarnings("unchecked")
private List<TextField<BigDecimal>> findFields(Form form) {
    List<TextField<BigDecimal>> fields = Lists.newArrayList();
    MarkupContainer container = (MarkupContainer) form.get("shares");
    for (Iterator<? extends Component> it = container.iterator(); it.hasNext();) {
        MarkupContainer c = (MarkupContainer) it.next();
        fields.add((TextField<BigDecimal>) c.get("share"));
    }
    return fields;
}

但是,上述方法中有三个有点丑陋的演员表,其中一个(Component - &gt; TextField<BigDecimal>)会产生“未经检查的演员”警告。

如果您可以清理此解决方案,或了解更好的方法,随时发表评论或发布其他答案

答案 2 :(得分:2)

到目前为止,我看到你没有在列表视图中设置reuse items属性;来自java doc:

  

如果真正重新渲染列表视图,如果窗口根本没有更改或者滚动(与分页相比),则效率更高。但是,如果修改listView模型对象,则必须手动调用listView.removeAll()才能重建ListItems。如果在表单中嵌套ListView,则ALLWAYS将此属性设置为true,否则验证将无法正常工作。

但是,您也可以使用Visitor迭代列表视图的子项。 Wicket始终跟踪您添加视图的组件。