Java 访问Wicket表单验证程序中任意数量的字段

Java 访问Wicket表单验证程序中任意数量的字段,java,validation,wicket,Java,Validation,Wicket,我需要验证几个类型为TextField(即百分比之和为100)的Wicket输入字段。有一到多个这样的输入字段;事情是,我不知道事先有多少 (简化示例) 私有类PercentageValidator扩展了AbstractFormValidator{ @凌驾 public FormComponent[]getDependentFormComponents(){ // ... } @凌驾 公共无效验证(表格){ 列表字段=//TODO //需要每个字段值的实际验证 } } ListView的Jav

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

(简化示例)

私有类PercentageValidator扩展了AbstractFormValidator{
@凌驾
public FormComponent[]getDependentFormComponents(){
// ...
}
@凌驾
公共无效验证(表格){
列表字段=//TODO
//需要每个字段值的实际验证
}
}
ListView的Java代码:

ListView<?> listView = new ListView<PropertyShare>("shares", shares) {
    @Override
    protected void populateItem(ListItem<PropertyShare> item) {
    // ... 
        item.add(new TextField<BigDecimal>("share", ... model ...));
    }
};
ListView ListView=新的ListView(“共享”,共享){
@凌驾
受保护的void populateItem(列表项){
// ... 
添加(新文本字段(“共享”、…型号…);
}
};
HTML:

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

</tr>

... 
%
我尝试在页面上的集合中保留每个文本字段,但这种方法失败了,因为封闭的
ListView
方法的
populateItem()
被调用,不仅页面是第一次创建的,所以重复的字段被添加到集合中。(我想不出一个简单的方法来保持它不重复。)

使用ListView的事实似乎也使在
validate()
方法中从表单对象查找字段变得有些复杂。我想我需要使用
form.get(“shares”)
获取ListView并遍历它的子级


访问中继器(如
ListView
)中包含的任意数量的字段的“正确方法”是什么?

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

确实如此。以下是查找“共享”字段的帮助器方法:

@SuppressWarnings(“未选中”)
专用列表findFields(表格){
列表字段=Lists.newArrayList();
MarkupContainer=(MarkupContainer)form.get(“共享”);

对于(迭代器,据我所知,您没有在列表视图上设置属性;从java文档:

如果为true,则如果窗口完全没有更改或滚动(与分页相比),则重新呈现列表视图更有效。但是如果修改listView模型对象,则必须手动调用listView.removeAll()为了重新生成ListItems。如果在表单中嵌套ListView,请始终将此属性设置为true,否则验证将无法正常工作


但是,您也可以使用一个。Wicket始终跟踪您添加到视图中的组件。

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

通过这种方式,您可以避免未经检查的强制转换,并且不必依赖ids,这不是一种非常健壮的方法

编辑:在实践中,它看起来像这样:

子类:

private static class ShareField extends TextField<BigDecimal> {
   // ...
}
私有静态类ShareField扩展了TextField{
// ...
}
从表单中查找所有共享字段的帮助器方法:

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;
}
private List findShareFields(表单){
最终列表字段=Lists.newArrayList();
form.visitChildren(ShareField.class,新的IVisitor()){
@凌驾
公共对象组件(共享字段组件){
字段。添加(组件);
返回继续遍历;
}
});
返回字段;
}

Wicket 1.4,如果有区别的话。感谢您指出
setReuseItems()
visitChildren()
方法,我也不知道。谢谢!我添加了一个与我的用例相匹配的代码示例。如果它不是最理想的,请随意改进。我认为代码看起来很整洁,而且即使快速浏览也能使其用途显而易见。
private static class ShareField extends TextField<BigDecimal> {
   // ...
}
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;
}