Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
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:
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.
which is perfect.
Whereas in Vaadin 8 scrollTo is:
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.
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...
I'd like to add a +1 on this. Promoting Grid/TreeGrid as a successor to Table/TreeTable is premature without this feature.
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!
[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.
AMahdy Abdelaziz: 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.
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 :-).
Vasiley Borschenko:
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 :-).
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.
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.
Vasiley Borschenko: 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,
Jean-Christophe Gueriaud: 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
AMahdy Abdelaziz:
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
I also thought about keeping the view instance but I don't know if it's possible (I can navigate from one view instance to another view instance so I don't want to keep too much instance of this view).
I will check if the solution can be used (easier to do that way :) ).
For grid or Vaadin objects, I like to do this way (found in some examples of code ;) )
public Grid<Person> getGrid() {
if (grid == null) {
grid = new Grid<Person>();...
}
return grid;
}
So I don't need to create a grid on constructor ou PostConstruct (for spring view) not on enter.
Jean-Christophe Gueriaud: I also thought about keeping the view instance but I don't know if it's possible (I can navigate from one view instance to another view instance so I don't want to keep too much instance of this view).
I will check if the solution can be used (easier to do that way :) ).For grid or Vaadin objects, I like to do this way (found in some examples of code ;) )
public Grid<Person> getGrid() { if (grid == null) { grid = new Grid<Person>();... } return grid; }
So I don't need to create a grid on constructor ou PostConstruct (for spring view) not on enter.
A singletone Grid might be a good trick, haven't tested that though but theoratically it should work as well :-) In General Vaadin stores the state on the server side inside the object, so that might sound like a lighter solution!
--
A^2
I believe that my situation is quite similar to yours.
On my application I'm trying to use a Wizard component with a Grid in the step one, but when the user is on step two and tries to get back the previous step he losts the previous state. What I did was to maintain the previous loaded grid data in a list in memory (cache) + selected the editing item with grid.select(item) option. But I can't scroll to the selected one.
If someone here has a better solution to do this please tell us here!
For this problem, I used grid-scroll-extension, save the scroll position and go to the saved position.
It's working if the data is in memory or with a lazy data provider.
but of your data changed then the scroll position will be wrong.
The thread is here:
https://vaadin.com/forum/#!/thread/16886923
Perhaps the best solution for a wizard is to keep the grid (so you won't lose the scroll position of the grid).
The workaround given in the github thread is working if you don't sort the grid.
Jean-Christophe Gueriaud:
For this problem, I used grid-scroll-extension, save the scroll position and go to the saved position.
It's working if the data is in memory or with a lazy data provider.
but of your data changed then the scroll position will be wrong.The thread is here:
https://vaadin.com/forum/#!/thread/16886923Perhaps the best solution for a wizard is to keep the grid (so you won't lose the scroll position of the grid).
The workaround given in the github thread is working if you don't sort the grid.
This not solve problem, which appear when added new item.
It's was very bad idea to make Vaadin grid with "virtual scrolling". With old good "paging" not so many problems.
Luckily this has been changed. At least the Vaadin 8.5.0.rc1 the Grid Javadoc for Grid.scrollTo(int)
reads:
* @param row zero based index of the item to scroll to in the current view.
So it appears that you can simply pass in 0 for the first row, 1 for the second row, etc.
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)?
Back to the original question.
From Vaadin 8.5+ there is getRowIndex() in Grid's item click event. That brings some symmetry to the API. I think it is the most common use case, i.e. you click an item and you want to do something with it.
I have the same issue with a grid (Vaadin 8.5.2): I need to keep selected rows selected and the selection visible after applying a value filter. I manage to restore the selection. For the scroll of the grid I tried the suggested workaround with the ArrayList conversion of getItems() of my Dataprovider. The suggested conversion (ListDataProvider) grid.getDataProvider()).getItems() does not work for me, as getDataProvider().getItems() is not defined. When using my DataProvider variable instead (defined as ListDataProvider), the conversion works, but the indexes I find are of course outside the bounds of filtered List and cause Exception. So my only solution will be to provide a pre-filtered List somewhere and change in DataProvider, which really seems a workaround outside the intentions of DataProvider to me. I would really appreciate a filter option preserving the selection and a method scrollTo(instance of Bean) instead of scrollTo(index).
The problem ListDataProvider#getItems() is, that it returns the backend list without filtering and sorting criteria applied. To take sorting and filtering into account the following implementation of scrollTo(bean) should work with ListDataProvider:
public void scrollTo(T item) {
DataCommunicator<T> dc = grid.getDataCommunicator();
List<T> items = dc.fetchItemsWithRange(0, dc.getDataProviderSize());
grid.scrollTo(items.indexOf(item));
}
Other implementations may also be possible by extending DataCommunicator (necessary because some methods needed are protected).
Thank you so much, Harry. I could implement it the way you recommended.
Nice to here it works for you - how about a thumbs up then :)