Повторно примените фильтр к ListDataProvider (для виджета Grid) в Vaadin Flow 14 - PullRequest
0 голосов
/ 07 февраля 2020

В веб-приложении Vaadin Flow 14 на макете есть виджет Grid, подкрепленный ListDataProvider.

Кажется, что когда я звоню ListDataProvider::setFilter, фильтрация вступает в силу немедленно. (Поправьте меня, если я ошибаюсь.)

listDataProvider.setFilterByValue(
        Product :: getLegacy ,      // Boolean property on my pojo `Product`. 
        this.legacy.getValue()      // `this.legacy` is a Vaadin `Checkbox` widget. The `getValue` method returns a `Boolean` (presumably). 
);

Мой фильтр основан на состоянии виджета Checkbox. Когда пользователь проверяет или снимает отметку с этого виджета, я хочу, чтобы фильтрация включилась, и в виджете Grid появилось больше или меньше элементов.

Я думаю, мне нужно добавить слушателя к виджету Checkbox. Я полагаю, это должен быть вызов либо addValueChangeListener или addClickListener. Или, может быть, addCheckedChangeListener?

➥ Мой вопрос: В этом слушателе, что я должен сделать, чтобы заставить фильтр повторно применяться к поставщику данных и, следовательно, изменить какие элементы появляются в моей сетке?

Должен ли я просто звонить clearFilters с последующим сбросом фильтра с вызовом на setFilter? Похоже, должен быть более прямой путь.

Вызов ListDataProvider::refreshAll, кажется, не имеет никакого эффекта. В моем прочтении документации этот метод должен вызываться (а) при изменении содержимого элементов, уже предоставленных поставщиком данных, или (b) при повторном заполнении группа товаров, предоставляемая поставщиком данных. Так что refreshAll кажется неуместным для моей цели. В моем виджете Grid содержимое ListDataProvider является неизменным. Я просто хочу показать / скрыть элементы в этой сетке, повторно активировав фильтр.

1 Ответ

2 голосов
/ 07 февраля 2020

Проблема

Проблема в вашем коде состоит в том, что строка this.legacy.getValue() захватила значение виджета Checkbox в тот момент, когда вы определяете этот фильтр. Значение для сравнения было извлечено из компонента, когда был установлен фильтр, и это значение остается тем же, даже если компонент обновляется. По сути, это то же самое, что если бы вы разбили его на две строки:

Boolean value = this.legacy.getValue();  // Captured once, not when user checks/unchecks the checkbox widget.
listDataProvider.setFilterByValue(Product::getLegacy, value);

Решение

Вам нужно захватить текущее состояние виджета Checkbox в тот момент, когда его значение меняется, когда оно было отмечено или не отмечено.

Примерно так: слушатель сбрасывает новый фильтр, используя текущее значение виджета.

this.legacy.addValueChangeListener(
    event ->
    listDataProvider
    .setFilterByValue(
        Product::getLegacy , 
        event.getValue()
    )
;

Вам не нужно делать clearFilters() между ними, поскольку все методы set очищают любые существующие фильтры. Существуют отдельные методы add, которые сохраняют существующие фильтры.

Вопреки тому, что вы указали в своем вопросе, метод refreshAll() действительно заставляет фильтр снова запускаться для всех элементов в поставщике. Вы можете использовать refreshAll() для повторной оценки фильтра, если фильтр определен таким образом, чтобы считывать текущее значение из компонента каждый раз, когда он вызывается.

listDataProvider.setFilter(
    product ->
    product.getLegacy().equals( this.legacy.getValue() )
);

Используя лямбду в этом В строке выше текущее состояние виджета-флажка legacy фиксируется на лету, когда фильтр выполняет сравнения по элементам в поставщике данных.

...