Is anyone using @FunctionalInterface Consumer<T> in complex UI component hierarchies?

Hi all,
I want to create hierarchies of complex reusable UI components.
What I struggle with is to decide how a button click triggers an action in the backend.

What I tried so far:

  1. Pass services/repositories down from top components to the buttons. The consequence is that some components might need to accept services/repositories in their constructor which they do not use .
  2. Have components raise events. This lets to components that have to catch events from lower components and to rethrow them.

What I did not test so far is to pass a consumer .

How do you handle this case? Is there any best practice/recommendation from Vaadin?

With non complex apps, I would just pass all needed services to the components that needs them. With more complexity, I still do it… but combined with prototype scope / route or UI scope to let my components be managed beans. With really complex and dynamic application I go with: https://cookbook.vaadin.com/ui-eventbus

Hello Knoobie, lets say you have a lot of events that could be raised by the components of the view.

How do you know for which ones to listen for?

ComponentUtil.addListener(
                    attachEvent.getUI(),
                    ButtonActivateEvent.class,
                    event -> {
                        if (event.getSource() != this) {
                            deactivate();
                        }
                    }
                );

This code then would like something like this:

ComponentUtil.addListener(
                    attachEvent.getUI(),
                    ClassX.EventY.class,
                    event -> {
                        if (event.getSource() != this) {
                            deactivate();
                        }
                    }
                );

But you dont even know that ClassX is used inside that view.

Is that something where you would just say: “Well that is what you have to know.”?

Also with events if you change data because of the event it might happen that you have to refresh the component that fired the event.

How do you do that?

And what does " With more complexity, I still do it… but combined with prototype scope / route or UI scope to let my components be managed beans." change vs just passing the services?

That would be exactly my answer :wink: keep in mind that you can pass literally anything inside those events or make them generic to allow for full flexibility

Simple: new CustomerLayout(service1, service2, repo, …) → my views have to upfront know any services / beans my components use

More advanced:
layout = Instantiator.getOrCreate(CustomerLayout.class) → my views know what components they need but not what type of services those need (making the views less super/god classes)

Normally you should not have a repository in your view/ component.

I tend to avoid creating spring bean for component, except for views and dialog. But it’s a personal preference

I’m with you on that - sadly I’ve seen literally hundreds of apps where even entities are used within the UI :cry:

I have some applications with entities in the UI. It’s a lot of boilerplate to transform entities to dto.

But it can be quite bad ( especially with a bad hibernate mapping :smiling_face_with_tear:)

I tend to use Consumer, functionalInterface for reusable component and no service. Also try to use services in a presenter and not in the view itself