Navigation Lifecycle

A number of lifecycle events will be fired while applying navigation from one state to another. The events are fired to listeners added to the UI instance and to attached components that implement special observer interfaces.

BeforeLeaveEvent

The first event fired during navigation is BeforeLeaveEvent. The event allows delaying or canceling the navigation, or changing the navigation to instead go to a different destination.

This event will be delivered to any component instance that implements BeforeLeaveObserver and was attached to the UI before the navigation starts. It is also possible to register a standalone listener for this event using the addBeforeLeaveListener(BeforeLeaveListener) method in UI.

One typical use case for this event is to ask the user whether they want to save any unsaved changes before navigating to some other part of the application.

Postpone

BeforeLeaveEvent has a postpone method, which can be used to postpone the current navigational transition until a specific condition is met.

E.g. the client may request the user’s confirmation before leaving the page:

public class SignupForm extends Div implements BeforeLeaveObserver {
    @Override
    public void beforeLeave(BeforeLeaveEvent event) {
        if (this.hasChanges()) {
            ContinueNavigationAction action = event.postpone();
            ConfirmDialog.build("Are you sure you want to leave this page?")
                    .ifAccept(action::proceed).show();
        }
    }

    private boolean hasChanges() {
        // no-op implementation
        return true;
    }
}

Postponing interrupts the process of notifying observers and listeners. When the transition is resumed, the remaining observers after the one which initiated the postpone will be called. As an example, let’s assume the current page has 3 observers a, b and c, which are being notified in this order. If b calls postpone, the call to c, as well as the rest of the transition process, is deferred. If the transition postponed by b is not resumed, c will not get a notification about this event at all and the transition never finishes. If, however, b executes its ContinueNavigationAction to resume the transition, it is continued from where it was interrupted. Thus a and b are not called again, but c is notified.

Note
At most one navigation event may be postponed at any time; starting a new navigation transition while a previous one is in a postponed state obsoletes the postponed state. After that, executing the ContinueNavigationAction kept from earlier will have no effect.

BeforeEnterEvent

The second event fired during navigation is BeforeEnterEvent. It allows changing the navigation to instead go to a different destination. This event is typically used for reacting to special situations such as if there is no data to show or if the user doesn’t have appropriate permissions.

The event is fired only after any postpone through BeforeLeaveEvent has been continued.

This event will be delivered to any component instance implementing BeforeEnterObserver that will be attached to the UI after navigation completes. Note that the event is fired before detaching and attaching components to make the UI match the location being navigated to. It is also possible to register a standalone listener for this event using the addBeforeEnterListener(BeforeEnterListener) method in UI.

Reroute

Either BeforeEnterEvent or BeforeLeaveEvent can be used to reroute dynamically if there is a need to show completely different information in some state. The event will not be fired any further listeners or observers after reroute. Instead, a new navigation phase will be triggered based on the new navigation target, and events will be fired based on that navigation instead.

In this example the reroute would happen when entering BlogList without any results.

@Route("no-items")
public class NoItemsView extends Div {
    public NoItemsView() {
        setText("No items found.");
    }
}

@Route("blog")
public class BlogList extends Div implements BeforeEnterObserver {
    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        // implementation omitted
        Object record = getItem();

        if (record == null) {
            event.rerouteTo(NoItemsView.class);
        }
    }

    private Object getItem() {
        // no-op implementation
        return null;
    }
}
Note
rerouteTo has several overloads to serve different use cases.

AfterNavigationEvent

The third and last fired event during navigation is AfterNavigationEvent. This event is typically used for updating various parts of the UI once the actual navigation has been completed. Examples of this include adjusting the contents of a breadcrumb component and visually marking the active entry in a menu as active.

The event is fired after BeforeEnterEvent and updating which UI components are attached. At this point, it can be expected that the current navigation state will actually be shown to the user, i.e. there will not be any further reroutes or similar.

This event will be delivered to any component instance implementing AfterNavigationObserver that is attached after completing the navigation. It is also possible to register a standalone listener for this event using the addAfterNavigationListener(AfterNavigationListener) method in UI.

public class SideMenu extends Div implements AfterNavigationObserver {
    Anchor blog = new Anchor("blog", "Blog");

    @Override
    public void afterNavigation(AfterNavigationEvent event) {
        boolean active = event.getLocation().getFirstSegment()
                .equals(blog.getHref());
        blog.getElement().getClassList().set("active", active);
    }
}