Vaadin Dataprovider:如何避免“自动获取"? [英] Vaadin Dataprovider: how to avoid "auto-fetch"?
问题描述
用例 1 的回答如下,用例 2 已移至单独的问题 (Vaadin Flow:返回视图,视图不应从后端重新加载数据)
Use Case 1 is answered below, Use Case 2 has been moved to a separate question (Vaadin Flow: Returning to a view, the view should not reload data from the backend)
我想使用由惰性 DataProvider
支持的 Vaadin Flow (v14 LTS/v19) 网格组件,该组件在显示网格时不会自动从后端获取数据.
I'd like to use a Vaadin Flow (v14 LTS/v19) grid component backed by a lazy DataProvider
which does not automatically fetch data from the backend when the grid is shown.
至少有两个用例:
- 除非用户提供过滤参数,否则显示网格数据没有意义
- 返回到
@PreserveOnRefresh
标记视图不应将显示的数据替换为当前数据.(在更新中进一步阐述)
- showing grid data does not make sense unless the user provided filter parameters
- returning to a
@PreserveOnRefresh
tagged view should not replace the shown data with current data. (further elaborated in update)
作为 Vaadin 14+ 的新手,我不知道如何实现这一点.每次显示我的 GridView
时,都会查询 DataProvider
的 count 和 fetch 回调.调用源自网格的 DataCommunicator
.
Being pretty new to Vaadin 14+, I could not figure out how to achieve this. Every time my GridView
is displayed, the count and fetch callbacks of DataProvider
are queried. The call originates from the DataCommunicator
of the grid.
那么对于用例 1:如何阻止 DataProvider
获取没有意义的数据?对于用例 2:如何防止在第二次向 UI 中添加网格时覆盖网格状态?
So for Use Case 1: How to stop the DataProvider
from fetching data as long as it does not make sense?
And for Use Case 2: How to prevent overwriting the grid state when adding a grid to the UI for the second time?
非常感谢!
StackTrace 到我的提取回调(Vaadin Flow 14):
StackTrace to my fetch callback (Vaadin Flow 14):
at org.vaadin.example.GridView.fetch(GridView.java:46)
at org.vaadin.example.GridView.lambda$new$c4b2c115$1(GridView.java:23)
at com.vaadin.flow.data.provider.CallbackDataProvider.fetchFromBackEnd(CallbackDataProvider.java:137)
at com.vaadin.flow.data.provider.AbstractBackEndDataProvider.fetch(AbstractBackEndDataProvider.java:61)
at com.vaadin.flow.data.provider.DataCommunicator.fetchFromProvider(DataCommunicator.java:362)
at com.vaadin.flow.data.provider.DataCommunicator.activate(DataCommunicator.java:647)
at com.vaadin.flow.data.provider.DataCommunicator.collectKeysToFlush(DataCommunicator.java:589)
at com.vaadin.flow.data.provider.DataCommunicator.flush(DataCommunicator.java:461)
at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$1(DataCommunicator.java:425)
at com.vaadin.flow.internal.StateTree.lambda$runExecutionsBeforeClientResponse$2(StateTree.java:390)
at [java.util.stream] omitted
at com.vaadin.flow.internal.StateTree.runExecutionsBeforeClientResponse(StateTree.java:387)
at com.vaadin.flow.server.communication.UidlWriter.encodeChanges(UidlWriter.java:411)
at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:187)
at com.vaadin.flow.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:122)
at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:91)
at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1547)
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:247)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
更新20210430这是我的 GridView
的代码,它也伪造了后端 DataProvider
:
update 20210430
Here's the code of my GridView
which also fakes the backend DataProvider
:
@Route(value = "grid", layout = MainView.class)
public class GridView extends VerticalLayout {
public GridView() {
final Grid<Person> g = new Grid(Person.class);
g.setColumns("name");
g.setDataProvider(DataProvider.fromCallbacks(q -> fetch(q), q -> count(q)));
add(g);
// filter omitted
final Button refresh = new Button("refresh");
refresh.addClickListener(e -> {
System.out.println("refresh clicked");
g.getDataProvider().refreshAll();
});
add(refresh);
add(new TextField("State check"));
}
// fake DataProvider
private int count(Query<Person, Void> q) { return 3; }
private Stream<Person> fetch(Query<Person, Void> q) {
q.getLimit(); //vaadin checks these have been called
q.getOffset(); //vaadin checks these have been called
System.out.println("fetching again");
new Exception().printStackTrace(); //figure out who called
return Arrays.asList(new Person("1"), new Person("2"), new Person("3")).stream();
}
}
我的MainView
用于在GridView
和EmptyView
@PreserveOnRefresh
public class MainView extends AppLayout {
private Component emptyBView;
private Component gridBView;
public MainView() {
final Button emptyB = new Button("Btn empty");
emptyB.addClickListener(e -> {
if (emptyBView == null) { emptyBView = new EmptyView();}
setContent(emptyBView);
});
addToNavbar(emptyB);
final Button gridB = new Button("Btn grid");
gridB.addClickListener(e -> {
if (gridBView == null) gridBView = new GridView();
setContent(gridBView);
});
addToNavbar(gridB);
}
}
MainView
是一个 AppLayout
用于将 AppLayout
的内容从 GridView
切换到 EmptyView
并返回.
MainView
is an AppLayout
used to switch the contents of the AppLayout
from GridView
to EmptyView
and back.
用例 2 是:当返回到 GridView
时,GridView
应该与之前的状态完全相同(这适用于 TextField
).
Use Case 2 is: When returning to GridView
, the GridView
should be exactly same state as before (which works fine with the TextField
).
- 打开
GridView
->网格不应填充数据 - 输入过滤器参数(代码中未显示)
- 点击刷新"填充网格
- 输入蜘蛛侠"在
TextField
中stateCheck" - 切换到
EmptyView
- 在实际应用中:在
EmptyView
和其他可能的视图中做一些事情 - 返回
GridView
->网格应该不重新加载数据,它应该保持原样 - 就像TextField
仍然显示蜘蛛侠"一样,网格应该显示与以前相同的数据无需重新加载.
- open
GridView
-> grid should not be filled with data - enter filter params (not shown in code)
- click "refresh" to populate the grid
- enter "Spiderman" in
TextField
"stateCheck" - switch to
EmptyView
- in the real app: do something in
EmptyView
and potentially other views - return to
GridView
-> the grid should not reload the data, it should just stay as it was - just like theTextField
still displays "Spiderman", the grid should display the same data as before without reloading it.
推荐答案
对于案例 1:在回调中检查是否有过滤器参数,如果没有则返回一个空集.使用新的 V17+ API,它看起来像这样:
For Case 1: In the callback check if you have filter parameters, return an empty set if not. Using the new V17+ API it would look like this:
grid.setItems(query -> {
if(filterParameters.isEmpty()) {
// Return an empty stream
} else {
// Fetch from backend
}
});
您可以在此处的文档中阅读更多内容:https://vaadin.com/docs/latest/flow/binding-data/data-provider (V19) 或 https://vaadin.com/docs/v14/flow/binding-data/tutorial-flow-data-provider (V14)
You can read more in the docs here: https://vaadin.com/docs/latest/flow/binding-data/data-provider (V19) or https://vaadin.com/docs/v14/flow/binding-data/tutorial-flow-data-provider (V14)
我需要更多关于您目前正在做什么的信息来帮助解决案例 2.您如何构建视图,您的代码是什么样的?带有Caused by"的完整堆栈跟踪也会有所帮助.
I would need more info on what you're currently doing to help out with Case 2. How are you constructing the view, what does your code look like? A full stack trace with the "Caused by" would also help.
这篇关于Vaadin Dataprovider:如何避免“自动获取"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!