I’m interested in exactly the same thing. I thought I can bind to Map but its not working. For Vaadin 7 I found something like this https://vaadin.com/forum#!/thread/89760 … is there a way how to bind to non PJO strucutures (Maps etc ?) in Vaadin 8
I’ve just bind a hashmap on x texfields (no validation, no metamodel…).
Here the code:
Map<String,String> mapExample = new HashMap<String,String>();
private VerticalLayout layout = new VerticalLayout();
Binder<Map<String,String>> binder;
/**
* Create a textfield
* - add it to the layout
* - bind the Map value to the textfield
*
* @param code
*/
private void createTextField(String code) {
TextField tf = new TextField();
tf.setWidth(250,Unit.PIXELS);
layout.addComponent(tf);
//bind element
binder.forField(tf).bind(// getter
list -> { return list.get(code);},
//setter
(list,fieldValue) -> {list.put(code, fieldValue);});
}
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
logger.debug("enter");
layout.removeAllComponents();
// create a sample map
mapExample = new HashMap<String,String>();
mapExample.put("FIELD1", "VALUE1");
mapExample.put("FIELD2", "VALUE2");
mapExample.put("FIELD3", "VALUE3");
// create the empty binder
binder = new Binder<Map<String,String>>();
for (Map.Entry<String, String> entry : mapExample.entrySet())
{
createTextField(entry.getKey());
}
// bind the sample bean to the list of textfields
binder.setBean(mapExample);
// test the result
Button b = new Button("PUSH", e -> {
for (Map.Entry<String, String> entry : mapExample.entrySet())
{
System.out.println("FIELD" +entry.getKey() + "-VALUE-"+entry.getValue());
}
});
layout.addComponent(b);
this.addComponent(layout);
}
Thanks for hint. One more question. How do you bind DateField . When I do it as below, I’m getting java.lang.ClassCastException: java.util.Date cannot be cast to java.time.temporal.Temporal error.
binder.forField(c) .bind(new ValueProvider<Map, Object>() {
@Override public Date apply(Map d) {
return (Date) d.get(field.getId()); } },
new Setter<Map, Object>() {
@Override public void accept(Map d, Object value) { d.put(field.getId(), value); } }); }
First of all, the key feature of Vaadin 8 is support for new Java 8 features. The API is supposed to be used with Java lambdas but not with inline classes. So,
binder.forField(c) .bind(new ValueProvider<Map, Object>() {
@Override public Date apply(Map d) {
return (Date) d.get(field.getId()); } },
new Setter<Map, Object>() {
@Override public void accept(Map d, Object value) { d.put(field.getId(), value); } }); }
binder.forField(c)
.withConverter(new AtoB())
.withConverter(new BtoString())
.bind( (data, value) -> data.get( field.getId() ), value-> data.put(field.getId(), value));
And, after all, Vaadin 8 uses new
LocalDate and
LocalDateTime classes instead of
Date wich makes code more respectful of timezones. If your database keeps dates in
Date objects, please convert the data first.
Unfortunately, you run into old part of the documentation specific to Vaadin 7. We will remove the pages, most probably.
Old, Vaadin7-compatible API still exists in Vaadin 8, in legacy packages (maven artifacts named vaadin-compatibility-server etc), but all that API is moved to com.vaadin.v7.* packages, and you can use the API if you still need that for some reason.
@Ilia : I think we lost the track - the question starting the thread was how to dynamically bind data without POJO, when Field type, converter, validators etc. are not known at compile time. It is possible, but IMO it’s a huge step back compared with Vaadin7. For example, you replaced the Property interface by the HasValue interface, that can be parametrized. But you removed the getType() API method that I need if the types are not known at compile time. You replaced the API by Java 8 compiler features. But that’s not the same!
Looking at your examples in the documentation, everything I see is a TextField bound with a String POJO property. Nice, simple Hello World example, all types are known at compile time, lambdas work as expected, we are writing less code compared to Vaadin7. In such a simple case yes. But the real code is typically more complex. For example, I do not save anything if I need to declare repeatedly a converter for all my non-string fields. Years ago we were advised from Vaadin consultancy to use a ConverterFactory. Introduced in Vaadin7, the API was removed without any replacement in Vaadin8. Now we have in our framework more than 100 Converters (not so bad, the V8 Converters are very similar) and we need to write our own Converter Factory mechanism. We save nothing. Neither money nor time. And who knows, maybe in Vaadin 9 you will replace the Binder with a SuperBinder changing again everything.
Changing public API without a workaround is always a bad idea.