0

In a vaadin table if we do

table.setRowHeaderMode(RowHeaderMode.INDEX);

we get a column with the row index.

Is it possible to to the same with a vaadin grid?

pbaris
  • 4,525
  • 5
  • 37
  • 61

5 Answers5

3

So far I haven't seen such an option, but you should be able to fake it with a generated column. Please see below a naive implementation which should get you started (improvements and suggestions are more than welcome):

// our grid with a bean item container
Grid grid = new Grid();
BeanItemContainer<Person> container = new BeanItemContainer<>(Person.class);

// wrap the bean item container so we can generated a fake header column
GeneratedPropertyContainer wrappingContainer = new GeneratedPropertyContainer(container);
wrappingContainer.addGeneratedProperty("rowHeader", new PropertyValueGenerator<Long>() {
    private long index = 0;

    @Override
    public Long getValue(Item item, Object itemId, Object propertyId) {
        return index++;
    }

    @Override
    public Class<Long> getType() {
        return Long.class;
    }
});

// assign the data source to the grid and set desired column order
grid.setContainerDataSource(wrappingContainer);
grid.setColumnOrder("rowHeader", "name", "surname");

// tweak it a bit - definitely needs more tweaking
grid.getColumn("rowHeader").setHeaderCaption("").setHidable(false).setEditable(false).setResizable(false).setWidth(30);

// freeze the fake header column to prevent it from scrolling horizontally
grid.setFrozenColumnCount(1);

// add dummy data
layout.addComponent(grid);
for (int i = 0; i < 20 ; i++) {
    container.addBean(new Person("person " + i, "surname " + i));
}

This will generate something similar to the image below:

Simulated row header

Morfic
  • 15,178
  • 3
  • 51
  • 61
  • It is better, instead of increasing `index`, to use `container.indexOfId(itemId)`. Otherwise when we sort the grid indexing is wrong – pbaris Apr 13 '16 at 08:43
  • @pbaris The code above is just a sample. Managing the value of that column depends on how you plat to implement the whole feature. For example if you have many records you may want to retrieve from DB pages of say 20 items instead of loading them all in memory. In this case even `container.indexOfId(itemId)` would probably not be correct. Instead an index based on the page number and item position would make more sense... – Morfic Apr 13 '16 at 09:05
  • I have implemented sorting and `LIKE` filters for an SQLContainer, and I was getting my datasource with an `(SQLContainer) grid.getContainerDataSource()` in order to add my filters to it. But now that my datasource is a `GeneratedPropertyContainer` that doesn't work anymore, and I'm terribly lost. I need a "generated index" in order to implement a custom buttom that would take me directly to the record belonging to a grid row. I can't believe this can be that difficult. I'm thinking on implementing that "row generator" directly in my SQL query, but it stinks... Any suggestions? – Pere Dec 28 '16 at 18:24
  • Unfortunately I have to comment on my own comment. Using a `GeneratedPropertyContainer` is a hassle because you have to wrap and unwrap every time you want to access the SQLContainer below it. Also this generated value moves when reordering or filtering by columns, so it's unuseful for getting the actual position or index of a row in the component. Still trying to find a proper solution. – Pere Dec 29 '16 at 10:24
2

There is a Grid Renderer that can be used to do this now. It is in the grid renderers add-on https://vaadin.com/directory/component/grid-renderers-collection-for-vaadin7. It is compatible with Vaadin 8 as well.

Here is how it could be used (there are a few different options for how to render the index). grid.addColumn(value -> "", new RowIndexRenderer()).setCaption("Row index");

zach
  • 21
  • 2
1

Worth to mention that I use the following with Vaadin 18 flow and works perfectly.

grid.addColumn(TemplateRenderer.of("[[index]]")).setHeader("#");
itro
  • 7,006
  • 27
  • 78
  • 121
0

Ok, it took me more than a while to figure this out. I don't know why you need this, but if your purpose is to find which grid row was clicked, then you can get the index from the datasource of your control via the itemClick event of your listener.

In my case, my datasource is an SQLContainer, and I already had it available (see ds var) so I did it this way:

grid.addListener(new ItemClickEvent.ItemClickListener() {
    @Override
    public void itemClick(ItemClickEvent event) {               
        Object itemId = event.getItemId();
        int indexOfRow = ds.indexOfId(itemId);                      
    }       
});

You usually add a datasource to your control when you initialize it, via constructor or by setting the property. If you got you Grid from somewhere with an already-attached datasource, you can always get it with something like this:

SQLContainer ds = (SQLContainer)gred.getContainerDataSource();
Pere
  • 1,068
  • 12
  • 20
  • 1
    The requirement was to have a column which displays the index of each row in a grid, just like [`RowHeaderMode.INDEX`](https://vaadin.com/api/com/vaadin/ui/Table.RowHeaderMode.html#INDEX) for tables. Most likely it's for displaying and/or navigation purposes only, for example excel sheets display such a row header – Morfic Dec 29 '16 at 11:54
  • Just for the sake of curiosity... doesn't your column get mixed up if you reorder or filter your data columns? – Pere Dec 29 '16 at 12:43
  • 1
    The sample in my answer is for _academic purposes_, meaning it's supposed to give you a starting point and you can implement it to fit your needs. For example, if you have lots of records (which is usually the case), then you'll implement some sort of pagination and do the sorting and filtering directly in the query instead of doing it on the items visible in the grid. Thus, the row indexes will probably be calculated based on the page number and item index... – Morfic Dec 29 '16 at 15:06
  • In fact, in my case, sorting and filtering is done directly in the query, and the calculated row indexes using your method never appear sorted, not even in the "default" case before trying any filtering or changing order. – Pere Dec 29 '16 at 16:21
0

I use this trick:

int i = 0;    
grid.addComponentColumn(object -> {
                i++;
                return new Label("" + i);
            }).setCaption("");