Vaadin 8 Grid.scrollTo(x) but, where is x?

I apologize if this has been asked; however, I cant seem to find this question anywhere. With Vaadin 8 grid, the dataProvider maintains backend data while what is displayed in the UI may be filtered and sorted entirely different from the backend. So, I have a sorted Grid of significant size and want to add an item, select the item, and then scroll to the items position within the sorted grid (ie x). Without implementing a bunch of listeners and maintaining a (hopefully) synchronized version of what is show in the UI, How do I find what row (int x) the new record is in so that I can call scrollTo(x)?

thanks.

Just started to think about moving to Vaadin 8, and ran into that puzzle too. In Vaadin 7 Grid’s scrollTo method looks like:

[code]
public void scrollTo(Object itemId) throws IllegalArgumentException
Scrolls to a certain item, using ScrollDestination.ANY.If the item has visible details, its size will also be taken into account.

Parameters:
itemId - id of item to scroll to.
[/code]which is perfect.

Whereas in Vaadin 8 scrollTo is:

[code]
public void scrollTo(int row) throws IllegalArgumentException
Scrolls to a certain item, using ScrollDestination.ANY.If the item has visible details, its size will also be taken into account.

Parameters:
row - id of item to scroll to.
[/code]where row is “id of item” of type int. What if in my backend data provider item’s id is not “int”? What is actually “row” - index within a grid? If it is, then how do I calculate it, as Joseph Craig rightly asks? If it is not, then what is the value of scrollTo(int row)?

Thanks!

Hi,
as you can read here https://github.com/vaadin/framework/issues/8820 and with a look in the source code of vaadin, there is no way to find the row keys actually. They are only maintained at client side.

In my projects this is also a huge drawback to have no scrollTo(T item) because if the user selected an entry in a grid with millions of entrys and switches the view forth and back there is no way to restore the view and scroll to the last selected position. In addition i think it is quite problematical that everything in the view is correctly restored except the scoll position… kind of weird for the customers…

Thanks Patrik,

At least it is on the radar…

I’d like to add a +1 on this. Promoting Grid/TreeGrid as a successor to Table/TreeTable is premature without this feature.

Me too +1
Actually really important I would say

I also a +1 on this github issue. That’s really important to return on the grid on the same row

Yet another ugly code:

grid.scrollTo(
  new ArrayList(
    ((ListDataProvider) grid.getDataProvider()).getItems()
  ).indexOf(obj)
);

This is just a suggested workaround, not sure yet how concrete it can work in many cases.

I’ve tried that with Grid and it seems work, but it does not with TreeGrid:

java.lang.IllegalArgumentException: Hierarchical data provider doesn’t support non-hierarchical queries
at com.vaadin.data.provider.HierarchicalDataProvider.size(HierarchicalDataProvider.java:51)
at com.vaadin.ui.Grid.scrollTo(Grid.java:3938)
at com.vaadin.ui.Grid.scrollTo(Grid.java:3917)…

Thanks for the suggestion!

Code snippet to reproduce?

[size=2]
private TreeData<Parameters> treeData = new TreeData<>();
private TreeDataProvider<Parameters> treeDataProvider = new TreeDataProvider<>(treeData);
...
protected boolean setSelectedItem(final Parameters pParams)
{
  final Parameters item = treeData.getRootItems().stream()
                          .filter(params -> params.matches(pParams))
                          .findFirst().orElse(null);
  if (item != null)
  {
    select(item);

//  This throws the exception in my ealier post
//    scrollTo(treeData.getRootItems().indexOf(item));

//  This throws the exception below
/*    scrollTo(  new ArrayList<Parameters>(((ListDataProvider) getDataProvider()).getItems())
               .indexOf(item)  ); */

    return true;
  }

  return false;
}
[/size]

Thrown exception: com.vaadin.data.provider.TreeDataProvider cannot be cast to com.vaadin.data.provider.ListDataProvider

Thanks for the suggestions!

Yes, the default data provider for Grid is ListDataProvider, which also have conventient getItems() method. Tree and TreeGrid use TreeDataProvider. Simple change of casting wont help here, since TreeDataProvider does not have getItems() method.

When I look at my first suggestion, I feel a lot of performance issues if you keep it as it is. Best way of using it it to keep track of:

items = new ArrayList( ((ListDataProvider) grid.getDataProvider()).getItems() ); And search the index in the list whenever you want to
scrollTo
.
But then you need to update the
items
whenever the data is modified. For example, everytime you:

grid.setItems(..) or

grid.refreshItems(..) you also make sure to update
items
.

Same applies to
TreeGrid
. First keep track of the list:

TreeGrid tg = new TreeGrid(); TreeData td = ((TreeDataProvider) tg.getDataProvider()).getTreeData(); List items = new ArrayList(); td.getRootItems().forEach(r -> { items.add(r); items.addAll(td.getChildren(r)); }); And you will have
items
to search in their index for the row, and as previous, make sure to alwyas update them.

Is this the best code? No.
What is the best way of doing it? The framework should implement this. Hopefully those are a temporarily workarounds.

If the backend contains 100K then you defintely don’t want to
grid.setItems(listOf100K)
. You must implement a custom DataProvider, and in this case, with custom row index retrival method from the database directly. Same if you use lazy loading.

Imagine your backend contains 100K or 1M of items. Or behind your backend stands some database that doesn’t support
‘row_number() over’-like construction, which by itself can be quite time-consuming. These circumstances can become serious obstacles for migration attempts. Let us all hope there will be a permanent solution at last :-).

I didn’t try to question your concrete workaround proposals with ArrayList. I just wanted to say, that if you have a really large dataset /e.g. database/ there may occur serious problems with a ‘custom row index retrival method’. Which in its turn may lead to inability of migration to Grid 8.

Yes, this is true. If you want to implemente scrollTo(item) fast, it requires internal hash map. The negative thing with hash map is that it increases the memory footprint, and hence impacts application scalability. And you do not need this ability in all applications. Hence I tend to think, fast implementation of scrollTo(item) should be optional. I.e. there should be API to enable it and only in that case more memory consuming, but faster implementation is used. In default case normal O(n) search of item would be used.

Hi,

I have got the same kind of problem:
I have a lazy backend provider. I would like to change my view and go back to this view with the same scroll position.
In the grid, there is scrollTo (index of the item) but I don’t know the index of the item.
Is it possible to get the current position of the grid ? (I don’t see anything in java perhaps there is something with javascript).

Thanks,

With respect to the explanation provided by Tatu earlier, the memory footprint issue and the speed of search. In this particular case I’d assume that keeping the view in the memory might be a better solution.
This way, whenever you return back to the view, its state will be preserved and retrieved from the memory.
The trick is to instead of using this code:

navigator.addView("TheView", TheView.class); use this:

navigator.addView("TheView", new TheView());

TheView will be preserved in the memory through out the session, and it’s not recommended to do so with other views.


A^2

Please note that enter() method will still be called, so building the grid should not be done there. In the constructor instead of similar init methods (e.g. PostConstruct …etc).


A^2