Skip to content

CodeRADEvents

Steve Hannah edited this page Jul 6, 2021 · 3 revisions

Events

CodeRAD apps are event-driven. Events are used for most communication between loosley-coupled components. Some events originate from the user via interaction with the view. Such events are dispatched and propagated up the controller hierarchy until it is either consumed or it reaches the top of the hierachy (i.e. the application controller).

The following diagram depicts this flow in a scenario where the originating UI component doesn’t have a dedicated ViewController. In this scenario a user event occurs, so the event propagates up the UI hierarchy until it reaches the Form, which has a FormController, so the event is passed to that FormController, which processes it and passes it to its parent controller, which is the ApplicationController.

EventPropagationFlow
Figure 1. Example event flow where the component triggers an event, and it is dispatched to the Form’s registered FormController.
Note
In this diagram we know that none of Containers in the "up-line" between the Component and the Form have a registered ViewController, because if one had, then the event would have been passed to that view controller first, rather than propagating directly to the FormController.

The next digram shows a more complex scenario where the UI component has its own ViewController.

EventPropagationFlow2
Figure 2. Example of event flow when triggering component has a registered ViewController.

In this case the event is passed to the component’s ViewController first. It processes the event and passes it up to the FormController, which processes it and propagates it up to the ApplicationController.

Note
If the event had been consumed at any step, the propagation would be cancelled. E.g. If the ViewController had consumed the event, then it would not be passed to the FormController for processing.

The next example adds an additional FormController to the navigation stack. In this case, the event will propagate up through the FormController’s parent FormController before it reaches the ApplicationController.

EventPropagationFlow3
Figure 3. Example event flow with two levels of FormController in the controller hierarchy. The event passes through both FormControllers on the way up to the ApplicationController.

"Action" Events

The most common type of event is one that is triggered by an Action. CodeRAD provides special support for this type of event. See Actions for more information about Actions.

Handling Events

Tip
This section describes handling events that do not originate from an action. For action event handling see Actions.

The most direct way to handle events is to override the actionPerformed() method of a controller. A typical pattern is to check for a particular type of event, and then handle it.

The following is a sample from the Tweetapp demo’s application controller:

public void actionPerformed(ControllerEvent evt) {

    with(evt, StartEvent.class, startEvent -> {
        if (!startEvent.isShowingForm()) {
            startEvent.setShowingForm(true);
            if (lookup(TweetAppClient.class).isLoggedIn()) {
                new HomePageController(this).show();
            } else {
                new WelcomePageController(this).show();
            }
        }

    });
    super.actionPerformed(evt);
}
Tip
This snippet uses the NonNull.with() method, which checks if the evt object is an instance of StartEvent, and, if so, calls the provided callback.

In the above snippet, we handle the StartEvent, which is triggered when the app starts or resumes from the background.

Important
Notice that the call to super.actionPerformed(evt) occurrs at the end of the method. This ensures that we process the event before it is propagated up to the parent controller in the hierarchy.

You can also handle events using the addEventListener() method.

For example, we could rewrite the above snippet without overriding the actionPerformed() method as follows:

@protected
void onStartController() {
    // The onStartController() method is run when the controller
    // is started.  This is a good place to add event listeners.
    super.onStartController();


    this.addEventListener(evt -> {
        with(evt, StartEvent.class, startEvent -> {
            if (!startEvent.isShowingForm()) {
                startEvent.setShowingForm(true);
                if (lookup(TweetAppClient.class).isLoggedIn()) {
                    new HomePageController(this).show();
                } else {
                    new WelcomePageController(this).show();
                }
            }

        });
    });
}
Tip
In the above snippet we override the onStartController() method of the controller, which is run when the component is started. This is a good place to add things like event listeners.

Dispatching Events

The easiest way to dispatch an event is using the ActionSupport.dispatchEvent() method. This method will use the event source to determine the target Controller for the event, and deliver it there. Once delivered to the Controller, the event will be processed and propagated up the hierarchy until it is either consumed or it reaches the top.

Example: a "back" button that will dispatch a FormBackEvent, which will be handled by the nearest FormController to navigate "back" to the previous/parent form.
Button back = new Button();
FontImage.setIcon(back, FontImage.MATERIAL_ARROW_BACK_IOS, -1);
titleBar.add(BorderLayout.WEST, back);
back.addActionListener(evt->{
    evt.consume();
    ActionSupport.dispatchEvent(new FormController.FormBackEvent(back));
});

Available Event Types

The event system is extensible, and is intended to make it easy to add your own event types. See the ControllerEvent javadocs for a list of core event types. They are listed in the Direct known subclasses.

Some common core event types include:

ApplicationControllerEvents

InitEvent

Triggered when the app is first launched.

StartEvent

Triggered when the app is launched (after the InitEvent), or resumed (i.e. returns from the background).

StopEvent

Triggered when the app is stopped or paused (sent to background).

DestroyEvent

Triggered when the app is destroyed.

FormController Events

FormBackEvent

Triggered when a "back" button is pressed. This is handled by the nearest FormController to the event site.

FormShownEvent

Triggered when the FormController’s Form is shown.

AppSectionController Events

ExitSectionEvent

Triggered when request is made to "exit" the current section of the app. Typically in response to a button. This is handled by the AppSectionController, and usually navigates back to the nearest FormController that is a parent of the AppSection.

Clone this wiki locally