Wiki Markup |
---|
{scrollbar}
h1. Data Binding and Model-View-Controller Framework
As the XUL framework progressed, Pentaho developed a need for a clean, underlying model-view-controller (MVC) architecture application. MVC provides for a clean separation between application data (models), view logic (controllers) and the user interface (views). This separation creates loosely coupled components that are easier to maintain and test. For a more in-depth look at building Pentaho XUL applications with the MVC pattern, please refer to the excellent MVC in XUL applications article by Aaron Phillips: [http://wiki.pentaho.com/display/PLATFORM/MVC+in+Pentaho+Xul+Applications]
At the heart of any MVC application framework lies a method for synchronizing data between the models and views. Many frameworks leave this "housekeeping" to the developer. XUL bindings offer a more developer-friendly approach.
h2. What's in a Binding?
A XUL binding object consists of four primary and two optional pieces of data:
* Two *XulEventSource* objects -- one "Source," the other "Target" -- and a property for each to "Bind" together.
* A binding strategy (one-way, bi-directional, or bind-once).
A converter object to manage data translation between the two is also an option.
h2. Creating a Binding Object
There are several methods for creating a binding object in the XUL framework. Some are as simple as calling *bind()* with four strings from an event handler. All of those methods are covered in the aforementioned MVC document. Below is the most basic representation of a binding:
{code}
Binding bind = new Binding(sourceObject, "firstName", targetObject, "value");
{code}
When added to a binding context (explained later in this guide) it will synchronize data between *sourceObject* and *targetObject* by way of *firstName* and *value* respectively.
Because Java lacks first-class support for properties, and it's bad form to write objects with direct member access, a binding accesses data by way of the JavaBean standard. At the JavaBean level, the binding looks something like this:
{code}
sourceObject.getFirstName() => targetObject.setValue()
sourceObject.setFirstName() <= targetObject.getValue()
{code}
h2. Binding Strategies
By default, a binding object represents a synchronization bi-directionally. Any change to the source will update the target and visa-versa. You can optionally prescribe for a one-way binding between source and target as such:
{code}
binding.setBindingType(Binding.Type.ONE_WAY);
{code}
Where *ONE_WAY* is a type defined in Binding.Type enumeration. A one-way binding will send data from the source to the target but not the other way around.
Future versions will introduce the concept of a "bind-once" strategy that will in essence "flash" a snapshot of data between objects at the time of the binding's instantiation.
h2. Conversions
You can further extend the flexibility of your bindings by providing a *BindingConvertor* object to manage the translation of data between objects:
*BindingConvertor.java*
{code}
public abstract class BindingConvertor<V, R> {
...
public abstract R sourceToTarget(V value);
public abstract V targetToSource(R value);
}
{code}
Below is a simple implementation that binds the value of a *XulTextbox* with the *selectedIndex* of a *XulMenuList*. When a user enters a numeric string into the text box, it will be converted into an integer before being passed to the *setSelectedIndex* method of the menu list:
{code}
Binding binding = new Binding(textbox, "value", dropdown, "selectedIndex");
BindingConvertor conversion = new BindingConvertor<String, Integer>(){
@Override
public Integer sourceToTarget(String value) {
return Integer.parseInt(value);
}
@Override
public String targetToSource(Integer value) {
return value.toString();
}
}
binding.setConversion(conversion);
{code}
h2. The Binding Context
Bindings in and of themselves don't actually do anything; they simply describe the relationship between objects. The actual establishment of a binding is performed by a *BindingContext* object. However, you never have to deal with a *BindingContext* directly because every *XulDomContainer* has one. To add a new binding object to the context, simply pass the binding to the *addBinding()* method of the *XulDomContainer*.
{scrollbar} |
Page Comparison
General
Content
Integrations