Vaadin Grid - Attempted to fetch more items from server than allowed in one go - vaadin

~1500 data need to be fetched from DB. The code is pretty simple
List<Item> itemList = getItemsFromDB();
Grid<Item> grid = new Grid<>();
grid.addColumn(Item::getID).setHeader("Id").setAutoWidth(true);
grid.addColumn(Item::getName).setHeader("Name").setAutoWidth(true);
grid.setAllRowsVisible(true);
grid.setItems(itemList);
And I got this warning, only the first 1000 data are shown in the grid, the rest are just empty rows.
2022-04-15 15:46:52.475 WARN 19642 --- [nio-8080-exec-6] c.v.flow.data.provider.DataCommunicator : Attempted to fetch more items from server than allowed in one go: number of items requested '1583', maximum items allowed '1000'.
I know I can use lazy loading, but can I do it without it? The size of data will always be around 1500, and I don't actually care that much about how slow it is.
I am using vaadin 14.8.8

The problem comes from setAllRowsVisible and the DoS protection added inside the data provider. It's currently not easily possible to overwrite this without creating your own data provider.
I'm not really sure why you need all the rows visible; this increases the load time for your end user. If your only reason is to have the grid full height, you can just call setHeight on the grid and the let Vaadin handle the callbacks to the server to only fetch the amount of data needed to show on the client.

Related

Vaadin Grid (Multiselect): restore selection after refresh

A Vaadin grid shows data which is constantly updated by a background process. A user might select one or more rows to carry out various functions. The user might refresh the data from the backend (which updates rows shown in the grid).
The application needs to restore the selected items after a grid refresh.
grid.getSelectedItems() has to return the current instance of the selected items.
Refresh is implemented as follows:
void refresh() {
final var beanSet = grid.getSelectedItems();
dataProvider.refreshAll(); // refresh from backend
grid.asMultiSelect().select(beanSet); // restore previously selected items
}
Updating the grid works fine, but the selection is only partly restored: the "selected" checkbox is checked for the items in beanSet but querying grid.getSelectedItems() still returns the old instances.
Reproducer: https://github.com/skiedrowski/vaadin-grid-restore-selection, package com.example.application.views.idstyle -> check the notification after clicking "Update selected".
What is the correct way to update the selected items?
Context:
Vaadin Flow 23, Grid Pro in multiselect mode
grid items implement equals and hashCode based on an immutable id
grid data provider is a ConfigurableFilterDataProvider fetching paged data from backend
I believe the problem in your sample project is that you're always recycling a set of selected objects which contain the "old" data. You read out a reference to the old items in var beanSet = grid.getSelectedItems(); and store them back into the selection with grid.asMultiSelect().select(beanSet);
A lazy-loading Grid can't know if the programmatically set selection is a collection of objects that are available in the backend - it would need to fetch the entire backing dataset to do that. So when the selection is updated from the server, it could be any objects of the correct type, whether they actually exist in the data set or not.
What could do yourself is pass the selection set to the backend, update the items and then pass them back to the Grid's selection.
An open question that remains is whether Grid should update the selection when a fetch returns items that are equal to items in the selection. I can't immediately tell if that is
a) possible, or
b) a sensible thing to do
This is how we solve this in our application:
A]
fresh items are retrieved lazily
the only time when refreshed selection is needed is when we want to operate with the selected items (such as edit or another action, otherwise obsolete selected items don't matter)
the backend is able to return fresh item by ID
there is no need to update the selection on fetch() (which could introduce inconsistencies if a part of the selection is already updated but the rest haven't been fetched yet)
B]
we have some data providers which just hold wrappers for actual items
so any interaction with the items fetches fresh data under the hood
for the record, this was not done to solve this problem but mitigates it as a sideeffect

Angular 11 Material DataSource without further Requests to the Server

I've been playing around with the example table-schematic for the Material Design [version: 11.0.3] table.
Basically i want to make a request, take the response and display it with the options to sort and limit the displayed items (pagination).
It works fine if I just replace the content of the connect function with "return a mapped Observable of the Response" but then the sorting and pagination obviously don't work anymore (since they are deleted) and i can't figure out how to make them work.
I assume the example pagination and sorting requires the data to be already present when the page loads/initializes (e.g. with a static Array).
Putting the request in the connect() function, saving the objects of the response to a variable and subscribing does work. However the page does not update after filling the initially empty array with data until sorting or pagination settings change. Which would make sense to me.
My question is, how do i get the data in there once and use the same data for pagination and sorting.
Can I even use the schematic in this case or is it misleading?
You can initialize a MatTableDataSource using an array of data, and then it will handle paging, filtering, and sorting locally and not try to fetch any more data.
See this example: https://stackblitz.com/angular/nleleddqmel?file=src%2Fapp%2Ftable-overview-example.ts
This example creates the data array locally, but you would instead use the response from your server request.

Filtering Smarttables initial read request

im using a sap Smarttable to display my data from an ABAP Backend server. Additionally im using SmartVariantManagement to apply Variants and make them persistent.
The problem in my Application is the initial Load of the Smarttable. It seems like the table is first loading all the available data without any filters from the inital Variant of my Smartvariantmanagement.
Is there any way to apply the filters of Smartvariantmanagement to the initial Load in the Smarttable?
Or even better: Is it possible to shut down a running odata-read request if i apply a new selection in the smartfilterbar and just run the new one instead?
example 1:
you can avoid the initial request by the smarttable property
enableAutoBinding="false"
you can also set some mandatory fields for filtering, now the user performces an explicit call to the database
example 2:
you can also define a filter in the smarttable function
beforeRebindTable="onBeforeRebindTable"
controller:
onBeforeRebindTable: function (oEvent) {
var oBindingParams = oEvent.getParameter("bindingParams");
oBindingParams.filters.push(new sap.ui.model.Filter("PropertyX", "EQ", "myProperty"));
}
regards

How to deal with odata service created with 1000 rows of hana table in SAP hana XS app

I have a table of 1000 rows in Hana.
Then I created an odata service on that table using xsodata service to expose the data as odata.(working fine)
Now I want to use this on my XS app as list.
The problem is as there is 1000 rows the list is not loading all the data, it's showing the first record and the busy indicator showing 1/1000 more.
Error on console: getTimer is not a function. ( this part I did not get)
Now my question is how to get all the data(1000 rows) on the list, say loading 10 at first, and then I scroll down to show more.
Thanks
Good for you: Lazy loading is a built-in feature of SAPUI5 :)
Just add some extra properties to your list
<List id="contractList"
growing="true"
growingScrollToLoad="true"
growingThreshold="10"
items="{MyItems}">
<StandardListItem title="{MyTitle}" description="{MyDescription}" press="onPress" />
</List>
The growing property enables (or disables) the lazy loading.
The growingScrollToLoad enables loading via scrolling. If false, there is a button to load more items. The growingThreshold defines how many items will be fetched each time.
See the API for more information: https://openui5.hana.ondemand.com/docs/api/symbols/sap.m.ListBase.html
However this will not solve your other problem (getTimer is not a function). You should try to solve that before implementing lazy loading.
Also remember that for models containing more than 100 entries, you may need to set the limit using sap.ui.model.Model.setSizeLimit() to allow more than the 100 entries to be displayed.
Once your oModel is loaded with data add another code as below
oModel.setSizeLimit(500)

Vaadin - Table column order

Anybody know how to/or it is possible - create a Table with column specific order; configuration order which was before save - example in DB,
and uploaded at specific view on? also I wonder how to take generate this columns headers and content from POJOS class - beans.
Any good ideas?
setVisibleColumns
The Table::setVisibleColumns does double-duty:
Controls which columns are visible, and
Sets the order in which the columns appear.
Call Table::getVisibleColumns to see current ordering.
Doc
This is well described in:
Book of Vaadin > Table
Sampler > User Interface > Data Presentation > Table
Table API JavaDoc
Example Code
Basically, you need the code like this to control columns order and also set list of bean instances as datasource.
Code is not tested, just a demonstration. Valid for Vaadin 6, but I guess no significant changes comparing to Vaadin 7.
table = new Table();
// Wrap your beans collection into vaadin data container. There are many
// types of them , check Book of Vaadin.
BeanItemContainer<Bean> container = new BeanItemContainer<Bean>(Bean.class)
container.addBean(new Bean());
// Set collection of your beans as data source.
// Columns will be created for each property, vaadin uses reflection.
table.setContainerDataSource( container );
// You can select to display only properties you want, not all.
// Order matters. You can get columns list from any source - for example
// store in your DB.
table.setVisibleColumns( new Object[] {"prop1", "prop2"} );
// You can set column headers (by default vaadin will set them same as bean
// properties names). Order matters, should match above order.
table.setColumnHeaders( new String[] {"Property 1", "Property2"} );
The answer by Sergey Makarov is correct. This answer provides further information.
User’s Reordering
You may allow the user to drag-and-drop columns in a table to re-order them at runtime. To enable this feature, call isColumnReorderingAllowed.
You can use a listener to be informed when such a reorder event occurs.
The user’s re-ordering lasts only for this work session. If you want to maintain the user’s order in future work sessions, you must somehow persist their desired order and apply the order when instantiating the table again.
Losing The Order
If you replace the data source of the table, your column order will be reset. You can get the current order before the change, then restore. Example code follows.
// Visible status & ordering.
java.lang.Object[] visibleColumns = this.exampleTable.getVisibleColumns();
// ------| Fresh Data |--------------
// Put fresh data into the Table.
this.exampleTable.setContainerDataSource( freshBeanItemContainer );
// ------| Restore Config |--------------
// Visible status & ordering.
this.exampleTable.setVisibleColumns( visibleColumns ); // Assumes the table has the same properties.
By the way, as with visibility and order, being collapsed will also be reset with fresh data. You may want to track and restore column collapsing as well as ordering.

Resources