3.8. Behavior

Behaviors provide the ability to change how Controls behave at runtime.

Behavior is an interface that provides interceptor methods for certain Control life cycle events. These interceptor methods can be implemented to decorate and enhance the control and its children. This allows for making changes to Controls such as adding/removing JavaScript and CSS Elements, adding/removing attributes, etc.

Behaviors are added to Controls through the AbstractControl.addBehavior(Behavior) method, and the same Behavior can be shared by multiple Controls.

The Control, AbstractControl and Behavior, classes are shown in the figure below.

Behavior Class Diagram

Figure 3.5. Behavior Class Diagram


Control exposes the following Behavior related methods:

AbstractControl contains a Set that holds the Behaviors added to the Control. It also exposes the following methods for managing Behaviors:

The Behavior interface (interceptor methods) is covered next:

3.8.1. Behavior Execution

When a Behavior is added to a Control, the Control is automatically registered with the ControlRegistry. Registering with the ControlRegistry allows the Click runtime to quickly and easily access controls that have Behaviors and process them. Controls without behaviors won't be registered and won't be processed.

Click will invoke all the registered Behavior's interceptor methods at the appropriate time during the Control life cycle.

3.8.2. Behavior Example

Let's look at a simple Behavior example. Say we want to put focus on a Field in our Form. Normally we would use the following JavaScript snippet somewhere in our page template:

        document.getElementById('form_nameField').focus();

If we want this behavior on another page we can copy and paste this snippet to the other page template and update the field ID. Alternatively we can create a custom FocusBehavior that adds the necessary JavaScript to a target Field:

    public class FocusBehavior implements Behavior {

        public void preRenderHeadElements(Control control) {
            String id = control.getId();
            JsScript jsScript = new JsScript("document.getElementById('" + id + "').focus();");

            // Set script to execute as soon as browser dom is ready. NOTE: The
            // JavaScript logic determining when the DOM is ready is added by
            // the Form control, through the script '/click/control.js'.
            script.setExecuteOnDomReady(true);

            // Add the JavaScript element to the Control
            control.getHeadElements().add(jsScript);
        }

        ...
    } 

Below is an example using the FocusBehavior:

    public class MyPage extends Page {

    private Form form = new Form("form");
    private TextField nameField = new TextField("nameField");

        public MyPage() {
            addControl(form);
            form.add(nameField);

            // Create the custom behavior
            FocusBehavior focus = new FocusBehavior();

            // Add the behavior to the field
            nameField.addBehavior(focus);
        }
    } 

At runtime the nameField will be registered with the ControlRegistry when the FocusBehavior is added to the field.

Before the Control's HEAD elements are rendered, Click will invoke the FocusBehavior interceptor method, preRenderHeadElements(Control), passing the nameField as an argument.

The FocusBehavior preRenderHeadElements method will add the JavaScript code to the Field HEAD elements which will be rendered as part of the server response.

Our JavaScript snippet is executed by the browser as soon as the DOM is ready, in other words after our nameField has been rendered. Focus will be set on the nameField.