We should evaluate whether the benefits of a fluid api for the HTML components would outweigh the inconsistencies caused by overriding.
The test added to #555 shows that there will be no way to implement fluent API for components "correctly" (make component parameterized so that setters return parameter type not current one).
So
public class Div<D extends Div> extends HtmlComponent {
public D setWhatever(){
}
}
won't work.
So it's better to use Builders instead.
Added to the backlog
Affects #495 and #494
There is a way to add a Fluent API, completely out of the inheritance. The same could be used to add a DSL for Kotlin later ( additionally dependency). I created the solution and it looks like the following...
private final VerticalLayout layout = new VerticalLayoutBuilder(VerticalLayout::new)
.setDefaultHorizontalComponentAlignment(Alignment.START)
.setSizeUndefined()
.add(new HorizontalLayout(username , password))
.add(rememberMe)
.add(new HorizontalLayout(btnLogin , btnCancel))
.build();
private final Button btnCancel = new ButtonBuilder(Button::new)
.setId(BTN_CANCEL_ID)
.addClickListener(e -> clearFields())
.setText(getTranslation(BTN_CANCEL_CAPTION))
.setVisible(true)
.build();
Thanks for the effort @svenruppert ! but personally, I would hate having to write the following to instantiate something
new VerticalLayoutBuilder(VerticalLayout::new)
and I would never use this. There needs to be a simpler way. (less is more)
And as someone commented on our Slack, this would be a good thing to pitch as an add-on. IMO not part of @mstahv's Viritin, but something separate so that it would be possible to see how many people opt to use it. Viritin has bunch of other stuff too that make it harder to see what features should be promoted as official framework features.
ok
A builder API could be made in a way that typically doesn't require the new VerticalLayoutBuilder(VerticalLayout::new) step, even though it would be kept there for the really advanced cases. Instead, there could be static builder factory methods in the class itself. In that way, the examples could be changed to look like this:
private final Button btnCancel = Button.builder(getTranslation(BTN_CANCEL_CAPTION))
.setId(BTN_CANCEL_ID)
.addClickListener(e -> clearFields())
.setVisible(true)
.build();
private final VerticalLayout layout = VerticalLayout.builder()
.setDefaultHorizontalComponentAlignment(Alignment.START)
.setSizeUndefined()
.add(new HorizontalLayout(username , password))
.add(rememberMe)
.add(new HorizontalLayout(btnLogin , btnCancel))
.build();
The biggest challenge in any way is that we would have to ensure the builder classes are always in sync with the actual components. It might be possible to use some kind of code generation library for automating this, but I'm not too familiar with such things.
Sure, the solution from me was assuming that there is no change in the existing framework and to support extended Components.
To keep them in sync, I started working on an AnnotationProcessor. It is not too difficult.. With this approach, we could add support for custom components as well. (maybe a Pro)
Just leaving this here as a plug for a great existing Kotlin DSL for Vaadin:
Most helpful comment
There is a way to add a Fluent API, completely out of the inheritance. The same could be used to add a DSL for Kotlin later ( additionally dependency). I created the solution and it looks like the following...