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.
Control exposes the following Behavior related methods:
getBehaviors() - returns the Control's Set of Behaviors
hasBehaviors() - returns true if the Control has any Behaviors
AbstractControl contains a Set
that holds the
Behaviors
added to the Control
.
It also exposes the following methods for managing Behaviors
:
addBehavior(Behavior) - adds the given Behavior to the Control's Set of Behaviors
removeBehavior(Behavior) - removes the given Behavior from the Control's Set of Behaviors
The Behavior interface (interceptor methods) is covered next:
preResponse(Control) - defines an interceptor method that is invoked before the response is written.
preRenderHeadElements(Control)
- defines an interceptor method that is invoked after preResponse()
but before the Control
getHeadElements()
is called. This is a good place to add custom JavaScript or CSS elements
to Controls.
preDestroy()
- defines an interceptor method that is invoked before the
Control
onDestroy()
event handler. This interceptor method allows the behavior to cleanup
any resources.
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.
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.