vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
617 stars 167 forks source link

Add "mixin" interface `HasAttributes`, implement on `Component` and perhaps elsewhere #6455

Open basil-bourque opened 5 years ago

basil-bourque commented 5 years ago

The VaadinSession and VaadinContext classes both offer the ability to store state used during execution of our Vaadin web app. Both classes offer a key-value store of attributes, with methods setAttribute, getAttribute, and removeAttribute. This feature is quite handy as a place for Vaadin-using programmers to store session-scope state and context-scope state.

I suggest formalizing that behavior as a "mixin" interface named "HasAttributes". Retroactively define the two classes named above as implementing HasAttributes.

➥ More importantly, implement HasAttributes on the Component class.

As the superclass of both layouts and widgets, giving the Component class the ability to store arbitrary bits of state useful to a particular Vaadin-using app developer would be very handy, even vital in some scenarios.

The need might be as simple as storing some user-preference/setting local to a layout or other grouping of widgets.

Another use-case would be storing state per web browser window/tab, given that Vaadin enables multi-window apps. In Vaadin 8 era, the UI class provided this per-window/tab scope. In our subclass of UI, we could define our own variables or even our own key-value collection with a Map. But now in Vaadin Flow, we are not usually writing a UI subclass. Even if we tried, the new architecture of Vaadin Flow has intentionally made a UI instance replaceable with another, for example, when user clicks the browser Reload button — therefore, we cannot practically store useful state there as the instance can disappear at any moment. So now, in practice, for many of us building Vaadin Flow apps, our MainView class becomes the shell of our app, the container for all the content within a web browser window/tab. So that MainView takes the place of the old UI as representing the per window/tab scope of our app. As a layout, and therefore a Component, giving any MainView class the built-in capability to store and retrieve attributes as a key-value store would be quite handy.

A more exotic use-case might be when the Vaadin app is being built from generated code, or built as part of another framework. In my own work, I am building a translation tool to port apps from an old GUI framework and application development environment to Vaadin & Java. I am programmatically re-creating the views of the old app architecture as Vaadin layouts and widgets. So being able to store some state within my Vaadin layouts and widgets to tie them back to their legacy counterparts could be very useful.

The workaround would be the Vaadin-using programmer adding their own key-value collection management. Perhaps the various layouts or widgets could be extended in subclasses for this purpose by us Vaadin-using programmers. But given that Java lacks the ability to add methods to existing classes (such as Category in Objective-C), we would have to be writing many such subclasses. It makes more sense to have this behavior built into Vaadin itself.

As for performance and overhead impact, there not need be much impact. The underlying implementation of the key-value store is probably going to be a Map such as HashMap. That map object could be lazily instantiated, creating a new map only upon the first call to setAttribute for a particular Component instance.

basil-bourque commented 5 years ago

I found yet another need for this suggested HasAttributes interface: Consistency.

The VaadinSession class offers pairs of both setAttribute and getAttribute methods. Each is overloaded to take either a Class object or a String object as the key.

In contrast, the VaadinContext class has only a single setAttribute and getAttribute. Each takes only a Class as the key, with no option to use a String name as the key. This commission seems silly. Why not give the Vaadin-using programmer a way to store state conveniently by choice of either a Class or String key?

pleku commented 5 years ago

I'm in favor of adding something for supporting these use cases, but I have to admit I'm unsure of the suggested API of attributes since it collides a bit with the client side Element API attribute (for me). For Session it is part of the spec to have it as attribute though, so maybe it would be clear that this is for the same thing on the server side state for Component ? But I still wonder if someone would also expect that the data would be sent to the client also and made available there.

The same thing was kind of in V7 and V8 available with the setData API for Component. We felt that the API was named "badly" and was much misused to workaround all kinds of cases where the framework lacked a proper feature. That is why I would hope to know the concrete use cases that one would wish to achieve with this feature.

Once we have concrete examples, it should be quite straight forward for us to come up with an adequate design and then have this ready to go for development team or for external contributions to get it into the framework.