vaadin / flow

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

Allow accessing the UI in a less verbose way #9009

Open appreciated opened 4 years ago

appreciated commented 4 years ago

Description of the enhancement

Correct me if I am wrong, but every time if a developer wants to access the UI a verbose chain of methods has to be called. I personally get a bit frustrated while doing this over and over. This is meant as a constructive entry for a discussion, not because I think this is per se better. A possible solution could be to provide a shorthand method to get the same work done in a less verbose way.

Minimal reproducible example

The chain of methods look like this:

// If parent is a Component
getUI().ifPresent(ui -> ui.access(() -> {
    // Make changes to UI ...
}));

// Other use cases
UI.getCurrent().access(() -> {
   // Make changes to UI ...
});

Expected behavior

// If parent is a Component
accessUI[ifPresent](() -> {
    // Make changes to UI ...
}));

// Other use cases
UI.accessCurrent(() -> {
   // Make changes to UI ...
});

Versions:

- Vaadin / Flow version: independent
- Java version: independent
- OS version: independent
Legioth commented 4 years ago

The getUI().ifPresent(...) pattern is not recommended since it isn't threadsafe to call getUI() when not holding the session lock. It is unfortunately still quite widely used since it's very convenient. Relying on UI.getCurrent() is also not recommended since getCurrent() is not available from background threads.

Another factor to take into account is that UI.access is usually used in association with some background activity such as a subscription or a timer. In that case, one should preferably also ensure that the subscription or timer is closed if the user navigates away from that part of the application. This also means that navigating back should re-enable the subscription or timer. This leads towards setting things up in the onAttach method (or the corresponding listener) and then tearing things down in onDetach. When implemented in that way, the UI instance is directly avaialble through event.getUI().

I created a simple add-on that removes moste of the boilerplate from managing those attach and detach handlers. The application developer only needs to define a callback that is run inside the access task, a callback that sets up the subscription or timer, and finally the component instance for which to set up attach and detach listeners. It has been suggested to incorporate something based on this into the core framework, but this has so far not made it to the top of the backlog. The add-on is at https://vaadin.com/directory/component/accessor.