如何在 Vaadin Flow 中使用带有 DataProvider 的自定义组合框过滤?
How to use Custom Combobox Filtering with a DataProvider in Vaadin Flow?
我们目前使用的是 Vaadin Flow 版本 12.0.7(由于某些原因我们无法升级)并且我们想要覆盖 ComboBox 组件的过滤机制。我的意思是,当用户在 ComboBox 中输入内容时,我们想更改搜索 ComboBox 后面的项目的方式。
我在看这个 Vaadin documentation 关于如何实现组合框的自定义过滤。更具体地说,Filtering by a string
部分看起来很有希望。
根据 Vaadin 文档,我们实现了一个自定义接口,用于调整 ComboBox 的搜索方法:
public interface CustomerDataFilter {
List<Customer> fetch(int offset, int limit, String filterText);
int getCount(String filterText);
}
这非常简单,几乎与文档示例匹配 1:1。
然后我们根据文档创建了一个方法来用数据填充ComboBox。还几乎使用了文档中的 1:1:
private DataProvider<Customer, String>
createDepartmentDataProvider(CustomerDataFilter service)
{
return DataProvider.fromFilteringCallbacks(query -> {
// getFilter returns Optional<String>
String filter = query.getFilter().orElse(null);
return service.fetch(query.getOffset(),
query.getLimit(), filter).stream();
}, query -> {
String filter = query.getFilter().orElse(null);
return service.getCount(filter);
});
}
我们在为ComboBox 初始化数据时调用上述方法。在这一点上,我们还实现了接口(尽管这可能很难看)。然而,我们不太确定如何使用这两种接口方法。我们的第一个目标是始终 return 所有项目并忽略任何特定的过滤,这就是我们始终 return 整个 sorted
列表的原因。这只是为了测试目的,看看我们是否改变了过滤。
public void updateCustomerList() {
List<Customer> sorted = CustomerService.getInstance().findAll();
//for initial sorting
sorted.sort(new CustomerComperator());
DataProvider<Customer, String> test = createDepartmentDataProvider(new CustomerDataFilter() {
@Override
public int getCount(String filterText) {
return 0;
}
@Override
public List<Customer> fetch(int offset, int limit, String filterText) {
return sorted;
}
});
customerCompany.setItems(sorted);
customerCompany.setDataProvider(test);
}
我们尝试将 getCount
值增加到 1
,但一旦我们将其设置为高于 0
,就会发生以下异常:
The number of items returned by the data provider exceeds the limit specified by the query (1).
我们的猜测是,我们必须以某种方式调整 getCount
和 fetch
方法,以使其实现我们的自定义搜索。这不会有问题,因为我们有 ComboBox 和 filterText
后面的数据。为什么我们也需要一个 getCount
方法以及我们如何绕过显示的异常,这让我们有点困惑?我们的想法是让 getCount
总是 return 像 10
并且在 fetch
return 我们的 sorted
列表的一个子集关于 filterText
.
任何人都可以详细说明/帮助我们如何为 ComboBox 实施自定义过滤或为我们指出正确的轨道吗?
感谢 Steffen Harbichs 的回答,我们找到了实现过滤数据提供程序的方法。基本上这就是它所需要的一切:
public void updateCustomerList() {
List<Customer> sorted = CustomerService.getInstance().findAll();
sorted.sort(new CustomerComperator());
customerCompany.setItems(sorted);
ListDataProvider<Customer> listTest = new ListDataProvider<>(sorted);
customerCompany.setDataProvider(listTest.filteringByPrefix(new CustomerProvider()));
}
CustomerProvider
只实现了适用的DataProvider接口。之后我们可以简单地应用 filteringByPrefix
方法来改变过滤行为。
您的方向是正确的,但您需要先了解 DataProvider
的概念。
在客户端(浏览器),Vaadin 请求在用户与之交互后在组合框中显示数据。请求的数据将类似于 'how many items are in the data?',即 count 查询。假设您有 100 件商品。现在下一个请求是 'give me the first 40 items to show',即 fetch 查询。组合框将显示 returned 项目。一旦用户向下滚动列表,就会发出另一个数据请求 'give me the next 40 items to show' 等
总而言之,首先要求 DataProvider
return 计算所有项目的数量,然后按需逐页获取数据。当用户输入过滤器时,这也适用。不同之处在于您的计数和提取查询应该考虑过滤器。
示例:用户输入过滤器 'xyz',现在只有 50 个项目匹配此过滤器(按名称或其他方式),因此您将 return 50 in count 方法并且您的 fetch 方法应该相应地过滤.
您遇到的异常只是指出您的获取方法 returned 的项目比 Vaadin 请求的项目多(查询参数中的 'limit' 参数)。这是因为您目前没有处理 offset/limit。
您有两种选择来实施您的数据提供程序:
使用 ListDataProvider
Vaadin 提供了ListDataProvider
,这是对列表的DataProvider
的实现。分页已经在实现中完成,您不必关心它。使用 filteringBy
方法根据输入的筛选文本筛选数据。
这种方式更简单,但无法扩展。这意味着如果你有很多项目,你将消耗大量内存和 CPU 因为整个数据都是从后端检索到列表中的。如果您预计您的商品数量较少,请采用这种方法。
或者实现你自己的 DataProvider
您可以实现自己的 DataProvider
。我建议首先扩展 AbstractBackendDataProvider
class (javadoc)。 sizeInBackend
和 fetchFromBackend
方法需要实现。注意 fetch 方法中实现分页的 offset/limit 参数。
如果您将分页委托给您的数据库(例如 SQL 或无-sql 数据库),则此方法是可扩展的。由于您只在内存中保留一页,因此内存占用量会很低。
我们目前使用的是 Vaadin Flow 版本 12.0.7(由于某些原因我们无法升级)并且我们想要覆盖 ComboBox 组件的过滤机制。我的意思是,当用户在 ComboBox 中输入内容时,我们想更改搜索 ComboBox 后面的项目的方式。
我在看这个 Vaadin documentation 关于如何实现组合框的自定义过滤。更具体地说,Filtering by a string
部分看起来很有希望。
根据 Vaadin 文档,我们实现了一个自定义接口,用于调整 ComboBox 的搜索方法:
public interface CustomerDataFilter {
List<Customer> fetch(int offset, int limit, String filterText);
int getCount(String filterText);
}
这非常简单,几乎与文档示例匹配 1:1。
然后我们根据文档创建了一个方法来用数据填充ComboBox。还几乎使用了文档中的 1:1:
private DataProvider<Customer, String>
createDepartmentDataProvider(CustomerDataFilter service)
{
return DataProvider.fromFilteringCallbacks(query -> {
// getFilter returns Optional<String>
String filter = query.getFilter().orElse(null);
return service.fetch(query.getOffset(),
query.getLimit(), filter).stream();
}, query -> {
String filter = query.getFilter().orElse(null);
return service.getCount(filter);
});
}
我们在为ComboBox 初始化数据时调用上述方法。在这一点上,我们还实现了接口(尽管这可能很难看)。然而,我们不太确定如何使用这两种接口方法。我们的第一个目标是始终 return 所有项目并忽略任何特定的过滤,这就是我们始终 return 整个 sorted
列表的原因。这只是为了测试目的,看看我们是否改变了过滤。
public void updateCustomerList() {
List<Customer> sorted = CustomerService.getInstance().findAll();
//for initial sorting
sorted.sort(new CustomerComperator());
DataProvider<Customer, String> test = createDepartmentDataProvider(new CustomerDataFilter() {
@Override
public int getCount(String filterText) {
return 0;
}
@Override
public List<Customer> fetch(int offset, int limit, String filterText) {
return sorted;
}
});
customerCompany.setItems(sorted);
customerCompany.setDataProvider(test);
}
我们尝试将 getCount
值增加到 1
,但一旦我们将其设置为高于 0
,就会发生以下异常:
The number of items returned by the data provider exceeds the limit specified by the query (1).
我们的猜测是,我们必须以某种方式调整 getCount
和 fetch
方法,以使其实现我们的自定义搜索。这不会有问题,因为我们有 ComboBox 和 filterText
后面的数据。为什么我们也需要一个 getCount
方法以及我们如何绕过显示的异常,这让我们有点困惑?我们的想法是让 getCount
总是 return 像 10
并且在 fetch
return 我们的 sorted
列表的一个子集关于 filterText
.
任何人都可以详细说明/帮助我们如何为 ComboBox 实施自定义过滤或为我们指出正确的轨道吗?
感谢 Steffen Harbichs 的回答,我们找到了实现过滤数据提供程序的方法。基本上这就是它所需要的一切:
public void updateCustomerList() {
List<Customer> sorted = CustomerService.getInstance().findAll();
sorted.sort(new CustomerComperator());
customerCompany.setItems(sorted);
ListDataProvider<Customer> listTest = new ListDataProvider<>(sorted);
customerCompany.setDataProvider(listTest.filteringByPrefix(new CustomerProvider()));
}
CustomerProvider
只实现了适用的DataProvider接口。之后我们可以简单地应用 filteringByPrefix
方法来改变过滤行为。
您的方向是正确的,但您需要先了解 DataProvider
的概念。
在客户端(浏览器),Vaadin 请求在用户与之交互后在组合框中显示数据。请求的数据将类似于 'how many items are in the data?',即 count 查询。假设您有 100 件商品。现在下一个请求是 'give me the first 40 items to show',即 fetch 查询。组合框将显示 returned 项目。一旦用户向下滚动列表,就会发出另一个数据请求 'give me the next 40 items to show' 等
总而言之,首先要求 DataProvider
return 计算所有项目的数量,然后按需逐页获取数据。当用户输入过滤器时,这也适用。不同之处在于您的计数和提取查询应该考虑过滤器。
示例:用户输入过滤器 'xyz',现在只有 50 个项目匹配此过滤器(按名称或其他方式),因此您将 return 50 in count 方法并且您的 fetch 方法应该相应地过滤.
您遇到的异常只是指出您的获取方法 returned 的项目比 Vaadin 请求的项目多(查询参数中的 'limit' 参数)。这是因为您目前没有处理 offset/limit。
您有两种选择来实施您的数据提供程序:
使用 ListDataProvider
Vaadin 提供了ListDataProvider
,这是对列表的DataProvider
的实现。分页已经在实现中完成,您不必关心它。使用 filteringBy
方法根据输入的筛选文本筛选数据。
这种方式更简单,但无法扩展。这意味着如果你有很多项目,你将消耗大量内存和 CPU 因为整个数据都是从后端检索到列表中的。如果您预计您的商品数量较少,请采用这种方法。
或者实现你自己的 DataProvider
您可以实现自己的 DataProvider
。我建议首先扩展 AbstractBackendDataProvider
class (javadoc)。 sizeInBackend
和 fetchFromBackend
方法需要实现。注意 fetch 方法中实现分页的 offset/limit 参数。
如果您将分页委托给您的数据库(例如 SQL 或无-sql 数据库),则此方法是可扩展的。由于您只在内存中保留一页,因此内存占用量会很低。