Handling Events

For handling user interaction, Vaadin Flow uses event-driven programming. User interaction with the UI in the browser causes events. Flow passes the events from the browser to the server-side, where your application code can handle them. You need to implement an event listener for each component that the user can interact with.

You can implement event listeners with regular classes, anonymous classes, lambda expressions, or method references.

Implementing an Event Handler

The traditional and verbose way to handle events is to implement an interface for the event type.

Each way of user interaction fires a different event type. For example, clicking a button fires a ClickEvent<Button> event. Such events can be handled by implementing a ComponentEventListener for the event type. The events are handled in the onComponentEvent() method.

An event listener needs to be added to the component with an event-type specific method add*Listener(), such as with addClickListener(). Many components also allow passing it in the constructor.

The following example shows how to implement a click listener as a local class:

Button button = new Button("Click me!");

class MyClickListener implements ComponentEventListener<ClickEvent<Button>> {
    int count = 0;
    @Override
    public void onComponentEvent(ClickEvent<Button> event) {
        event.getSource().setText("You have clicked me " +
                (++count) + " times");
    }
}
button.addClickListener(new MyClickListener());

add(button);

As shown in the example, you can access the originating component with getSource() from the event.

Lambda Expressions

Lambda expressions are the easy way in Java to implement interfaces that only have a single method to implement, which is the case with event listeners.

For example, a lambda expression can be used for handling button click events as follows:

Button button = new Button("Click me!",
  event -> event.getSource().setText("Clicked!!!"));
add(button);

Most components, like Button above, allow passing a listener to the constructor. For others, you need to use an add*Listener() method, such as addClickListener(), as in the other example earlier.

Using Anonymous Classes

Anonymous classes are another shorthand way to implement handlers. They are more explicit than lambda expressions with the parameter type, and can in that way make the code more clear. They can also have a state like normal classes.

The following example defines an anonymous class that inherits the Button.ClickListener interface.

Button button = new Button("Click me!",
    new ComponentEventListener<ClickEvent<Button>> () {
    int count = 0;
    @Override
      public void onComponentEvent(ClickEvent<Button> event) {
        event.getSource().setText("You have clicked the button " +
                                  (++count) + " times");
      }
});

add(button);

Most components, like Button, allow passing a listener to the constructor. For others, you need to use an add*Listener() method, such as addClickListener().

Note that to be able to access the component from the anonymous listener class, you can have a reference to the component that is declared before the constructor is executed, for example as a member variable in the outer class. You can also to get a reference to the component from the event object, as in the example above.

Handler Methods

You can also direct events to methods with method references:

class ButtonBar extends HorizontalLayout {
    public ButtonBar() {
      add(new Button("OK", this::ok));
      add(new Button("Cancel", this::cancel));
    }
    public void ok(ClickEvent<Button> event) {
      event.getSource().setText("OKed!");
    }
    public void cancel(ClickEvent<Button> event) {
      event.getSource().setText("Canceled!");
    }
}

add(new ButtonBar());