2012-05-30 4 views
3

Мне нужно проверить что-то о нескольких полях ввода Wicket типа TextField<BigDecimal> (а именно, что сумма процентов равна 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 
    } 
} 

Java код ListView:

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() прилагаемого значения ListView привел не только первую страницу, но и дубликаты полей добавляются в коллекцию. (Я не мог найти простой способ сохранить его без дубликатов).

Тот факт, что ListView также используется, как представляется, несколько усложняет поиск полей из объекта формы в методе validate(). Я полагаю, мне нужно получить ListView с form.get("shares") и повторить его дочерние элементы?

Что такое «правильный путь» для доступа к любому количеству полей, заключенных в ретранслятор, например ListView?

+0

калиткой 1,4 , если это имеет значение. – Jonik

ответ

5

Альтернативный подход заключается в подклассе TextField, а затем использовать Visitor для выделения всех компонентов-потомков вашего подкласса.

Таким образом, вы можете избежать неконтролируемого литья, и вам не нужно полагаться на идентификаторы, что не очень надежный подход.

Редактировать: на практике это будет выглядеть примерно так:

Подкласс:

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

метод Helper, который находит все ShareFields из формы:

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; 
} 
+0

Спасибо! Я добавил пример кода, соответствующий моему варианту использования. Не стесняйтесь улучшать его, если он субоптимальный. – Jonik

+0

Я думаю, что код выглядит довольно аккуратно, и даже быстрый взгляд делает его цель очевидной. – biziclop

2

Правильно, при написании вопроса мне стало ясно, что, просто пробивая детей из form.get("shares") и получив поле с идентификатором «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 ->TextField<BigDecimal>) производит «снят слепок» предупреждение.

Если вы можете очистить это решение или узнать о лучших подходах, не стесняйтесь комментировать или оставлять другие ответы!

2

Насколько я вижу, вы не установили свойство reuse items в виде списка; из java-документа:

Если истинный повторный рендеринг, просмотр списка более эффективен, если окна вообще не изменяются или прокручиваются (по сравнению с поисковым вызовом). Но если вы измените объект модели listView, вы должны вручную вызвать listView.removeAll(), чтобы перестроить ListItems. Если вы вставляете ListView в форму, ALLWAYS присваивает этому свойству значение true, поскольку в противном случае проверка не будет работать должным образом.

Однако вы также можете перебирать детей из списка с помощью Visitor. Wicket всегда отслеживает компоненты, добавленные вами в представление.

+0

Спасибо, что указали методы 'setReuseItems()' и 'visitChildren()', я тоже не знал об этом. – Jonik

Смежные вопросы