How to create a Grid without binder?

We are trying to see if we can move on from V7 to V14, but one of the mains problems are Grids, we can’t create these with randoms columns not related to ONE class/object/entity.

Example: There is a grid that has a resume of a lot of data

Company (String) — Employees (Company.employees) — IncomingsoutcomingsStatusLast Contact (User.name) — Last Contact (timestamp)

So, are we forced to create a POJO to represent this data in a Grid? and for EVERY non-entity related?

//view Class
	new Grid<CompatyResumeV1>();


private class CompanyResumeV1 {
	String name;
	Integer employees;
	BigDecimal incomings;
	BigDecimal outcomings;
	Status status; //Enum
	String lastContact; //User.nick
	Date lastTime; //this is retrieved from a Log
}

What is the work-around for V14 for these cases? because binder are just useful for basic CRUD views, I couldn’t find any example for complex scenarios

You could model your ValueProviders like this:

public class GridDynamicValueProvider implements ValueProvider<GridDynamicRow, Object> {

    private int columnIndex;

    public GridDynamicValueProvider(int columnIndex) {
        this.columnIndex = columnIndex;
    }

    @Override
    public Object apply(GridDynamicRow dynamicRow) {
        return dynamicRow.getValue(columnIndex);
    }

}

and the “POJO” like this:

public class GridDynamicRow {

    private List<Object> values = new ArrayList<>();

    public void addValue(String value) {
        values.add(value);
    }

    public Object getValue(int columnIndex) {
        return values.get(columnIndex);
    }
}

Of course the List<> can also be replaced with a better way like a proxy to the real data.

Hi Jose

It is entirely possible to define a generic Grid that does not rely on specific POJO classes. But as you say, there is no documentation or example codes for that so you will have to spend some time for implementation.
I have done it before and can assure you it is doable but quite complicated. And unfortunately I do not have permission to share my implementation for this. I wish I had, I’m quite proud of this one

All I can say is that I made a Grid of type Grid<Map<String, Object>>.
In the Map<String, Object> I used the String for the column name, and the Object for the value of the item for said column. I’m really sorry I cannot really explain it too well without showing code.
If you can find a way to transform your incoming data into a Set<Map<String, Object>> you can then use these for grid.setItems(…). (It’s going to need more than that! for example you need a list of column names for initializing the grid)

I used a similar implementation to Kaspar. However, in my case I created an encapsulating class to make it easier and the code cleaner. Something like:

class Data {
	private Map<String, Object> values = new HashMap<>();
	
	public void set(String key, Object val) {
		values.put(key, val);
	}
	
	public Object get(String key) {
		return values.get(key);
	}
}

Then you can use the grid like so:

Grid<Data> myGrid = new Grid<>();

This is coming from code in Vaadin 8. Changes were made to make it work in Vaadin 14 but the strategy used above did not change.

INPUTsys Chris Peter:

I thing that suggestion by Peter is much cleaner, less boilerplate. The idea of use a List (ArrayList) and work with “columnIndex” is faster than Maps.
With a list, it is possible to implement a generic “Grid Builder” utility, without having to know the “Keys” used in the Map

example

//List + columnIndex
g.addColumn(new GenericGridRowValueProvider(0));
g.addColumn(new GenericGridRowValueProvider(1));
g.addColumn(new GenericGridRowValueProvider(2));

//vs Map
g.addColumn(source -> (String) source.get("firstName"));
g.addColumn(source -> (String) source.get("lastName"));
g.addColumn(source -> (String) source.get("birthDate"));
//and u have to remember these keys wherever u try to retrieve the value from the item
//of course we could use "1", "2" or even better, a Map<Integer, Value> 

My preference for column index must be influenced by my many years using Swing, JTables and DefaultTableModel :wink:

But in my brief experience and testing I already found a few limitation related to:


public class GenericGridRowValueProvider implements ValueProvider<GenericGridRow, Object>


trying to add a NativeButtonRenderer that needs a ValueProvider<SOURCE, String>

Thank u all for your help and initial push that we all sometime need to catch the rhythm

Note, if you use ArrayList or HashMap instead of POJO in your Grid, you need to override getId() of the DataProvider to get it work correctly in corner cases. You can see Vaadin 8 example code here, in Vaadin 14 its done pretty much in similar fashion.

https://github.com/TatuLund/GridFlip/blob/master/src/main/java/org/vaadin/gridflip/MyUI.java#L227

Hi Jose, Hi Tatu,

My preference for column index must be influenced by my many years using Swing, JTables and DefaultTableModel :wink:

I know what you mean :slight_smile:

…you need to override getId()…

Thanks for the hint. getId() defaults to the item itself. Why isn’t that sufficient? Could you please explain that?

Thanks