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) — Incomings — outcomings — Status — Last 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
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.
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
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.