Binding data and configuration options

A coach view may be associated with a data binding and configuration options. The view context provides access to this data. To access binding data and configuration options you must use the JavaScript get and set functions. You cannot use JavaScript dot notation.

context.binding

The binding object, if defined, provides access to data that is bound to a view. There is at most one data binding declared for each view.

You can access data that is bound to a view by using the construct: this.context.binding.get("value"), where value is a special property name that returns the data binding. For example, if a view is bound to local.phoneBook.title, then the view can get the phone book's title as follows:

if (!! this.context.binding){
var title = this.context.binding.get("value")
}
The main reason for views to bind to data is so that the view can be notified if the bound data has been modified. The view framework detects data changes in the bound object, and automatically notifies the view by calling its change event handler function. It is important to note that these notifications will be sent to the view only if the binding object itself changes, but not if any of its properties or sub-properties change. The following sections discuss the different data types and outline the cases where additional code is required for the view to receive notification of a data change.

Binding to simple and complex data types

For simple data types such as strings and numbers, the view framework detects data changes and automatically notifies the view of the change. For example, when a view is bound to the simple string type local.phoneBook.title, the view's change() function is called with a change event that specifies that the title changed and its new value. All the views that are bound to local.phoneBook.title are notified.

For complex data types such as business objects, the view is notified only if the binding object itself changes, but not if any of its properties or sub-properties change. For example, assume that the view is bound to a complex object local.phoneBook, not a simple type like a String. The object phoneBook has several properties, one of which is title. If there is a change to the title property, the change function is not called, because the view is bound to the phoneBook object, not the title property. The change function is only called if the entire phoneBook object is changed. If you need a view to know if a property of a complex object has changed, you must manually bind the view to the property by using the bind() or bindAll() function. Note that you can use the bind() and bindAll() functions in the same way for configuration options.
Important: The bindAll() function only handles one level deep in the object tree, so if the object has multiple levels (nested objects), the coach view needs to call bindAll() multiples time for each object level.
bind(path, callback, [scope])
Notifies the view via callback if a specified property has changed. Scope is an optional parameter that specifies the context scope of the callback. Returns a handle to the callback.
bindAll(callback, [scope])
Notifies the view via callback if any property on the object has changed. Scope is an optional parameter that specifies the context scope of the callback. Returns a handle to the callback.

For the callback signature, see the function(event) topic.

The following example shows code that you might add to a view's load event handler to manually bind properties of a complex object:
   var binding = this.context.binding.get("value");  //this is a complex object
   this.property2Handle = binding.bind("property1.property2", function(e) {some code}, this);
   this.property3Handle = binding.get("property3").bindAll(this.myBindAllChangeHandler, this);
   ......
   this.mybindAllChangeHandler(event) { .....};
In the example, the view is bound to a complex object and sets a change handler to be notified if binding.property1.property2 (which is a string) changes. It also sets another change handler to be notified if any sub-property of property3 changes. In both cases the scope in which the change handler is called is the view's this scope.

Binding to a list type

When you bind to a list, the view is automatically notified when the entire List object changes. For example, consider that the view is bound to the list local.phoneBook.person[]. If a new person list is created and set to the view's binding, for example using the server script syntax tw.local.phoneBook.person = new tw.object.listOf.person(); the framework automatically notifies the view of the change.

Binding to list updates

To be notified when an element is added, removed, or replaced, you must manually bind the view using the bindAll() function. In the following code example, the view's listUpdated function is called whenever a list element is added, removed, or replaced.
var binding = this.context.binding.get("value"); //this is a List object
this.bindAllHandle = binding.bindAll(this.listUpdated, this);

Binding to list properties

In addition to the elements of a list, a list also has special properties, such as a property that defines the list elements that are selected by a user. The special properties are described in the following table.
Table 1. Special properties of a list
Property Type Description
listAllSelectedIndices Array The indexes of the list elements that are selected by a user. There can be more than one selected index. When you set listAllSelectedIndices, you pass in the indexes in an array. Use listAllSelectedIndices when updating the list selection.
listAllSelected Array An array of all the elements that a user has selected. Use listAllSelected to subscribe to a change to this property. This property is read-only.
listSelectedIndex Integer The index of the selected element. This value corresponds to the value of the index 0 element of the listAllSelectedIndices array. Use listSelectedIndex to subscribe to a change to this property. This property is read-only.
listSelected Object The selected element. This value corresponds to the value of the index 0 element of the listAllSelected array. Use listSelected to subscribe to a change to this property. This property is read-only.
The bindAll() function does not include these special properties.
To receive notification of a change in a special property, you can subscribe to the individual property using the bind() function. In general, it is sufficient to subscribe to one special property (that is, it is not necessary to subscribe to all of the special properties). The following example code could be added to a load event handler to call a view's indicesChanged function whenever the value of listAllSelectedIndices changes.
var binding = this.context.binding.get("value"); //this is a list
this.selectedIndicesHandle = binding.bind("listAllSelectedIndices", this.indicesChanged, this);

Accessing list elements

Lists are a collection of simple types or complex objects with properties. Use the following notation to get data from a list:
  • Use get("value") to get the list object. For example: list = this.context.binding.get("value")
  • Use get(index) to obtain the indexed element. For example: list.get(0) to obtain the first element.
  • Use get(property) to obtain the value of the property. For example: list.get("listSelected") to obtain the value of the listSelected property. Use similar syntax to obtain the values of all other properties.
  • Use items to get an array that represents the underlying elements of the list. For example, list.items. The data returned by items should not be modified.

List operations

The following APIs are used to modify a list and to get information about a list.
  • To add an object, use list.add(item). For example, this.context.binding.get("value").add(item)
  • To remove an object, use list.remove(index), For example, this.context.binding.get("value").remove(0)
  • To replace an object, use list.put(index, item). For example, this.context.binding.get("value").put(0, item)
  • To get the length of a list, use list.length().
  • To get an indexed element or property of the list, use list.get(index | property). For more information, see Accessing list elements.
  • To programmatically update the selected property in the list, use list.set(property). For example, this.context.binding.set("listAllSelectedIndices , [1, 2, 3]);

Cleaning up bound resources

When a binding is no longer needed, you can release the bound resources. Each bind or bindAll function returns a handle which can be used to clean up the binding. You should release the bound resources either in the unload() event handler, or each time the whole binding object is changed. When a binding data change occurs, a view needs to unbind the manual binding, and rebind to the context.binding object by calling bind and bindAll again. For example, add the following code in the change event handler:
if (event.type != "config"){
var binding = this.context.binding.get("value"); //this is a list
	// assumes that this.selectedIndicesHandle was initialized in the load function
  this.selectedIndicesHandle.unbind();
this.selectedIndicesHandle = binding.bind("listAllSelectedIndices", this.indicesChanged, this);
	// assumes that this.selectedIndicesHandle was initialized in the load function
this.bindAllHandle.unbind();
this.bindAllHandle = binding.bindAll(this.listUpdated, this);

}

Configuration options

In addition to data, views also can be bound to configuration options. A view can have multiple configuration options. For example, the label of a button control is a configuration property. The values for the configuration can be retrieved using the view's this.context.options object. The object context.options contains a predefined metadata property in addition to user-defined properties that are configurable for a view.
Table 2. Predefined configuration options of a view
Option Type Description
label String The label value of the view, if one exists
visibility String The visibility settings for the view. Valid values are: "DEFAULT" | "EDITABLE" | "REQUIRED" | "READONLY" | "NONE" | "HIDDEN". See The coach view context object. DEFAULT is the code equivalent to Same as parent that users see on screen in a Visibility list.
Important: Tables have a Disable click-to-edit configuration property. The default value is false, which means that Coach Views contained within that table use the visibility settings of the table. That is, the Coach Views in a given cell are READONLY until the user clicks in the cell. The Coach Views are then EDITABLE until the user clicks anywhere outside of the cell. The Coach Views revert to being READONLY. When Disable click-to-edit is true, these Coach Views use their own visibility settings.
Important: Setting the visibility to REQUIRED does not validate whether a user has entered or set a value. You must provide code that does this checking by, for example, implementing a validation service for the Coach that contains the Coach View.
labelVisibility String The visibility settings for the label. Valid values are "SHOW" | "HIDE"
helpText String The view can use this property as hover text
className String The CSS class name(s) specified. Normally a view does not need to use this as the CSS class names are inserted into the view's DOM attribute
htmlOverrides Map A name-value pair map that represents the HTML attribute specified. These name-value pairs are inserted into the view's DOM attribute
Configuration options are accessed and updated in the same way as binding data. For example:
  • To get a view's predefined options, use this.context.options._metadata.*. For example, to get a view's visibility option, use this.context.options._metadata.visibility.get("value");
  • To set a view's predefined options, use this.context.options._metadata.*. For example, to set a view's visibility option, use this.context.options._metadata.visibility.set("value", newValue);
  • To get a user defined configuration option, use this.context.options.myOption.get("value");, where myOption is the option name.
  • To set a user defined configuration option, use this.context.options.myOption.set("value", newValue);, where myOption is the option name.

To serialize the data binding object to a JSON string, you can call the toJson() function on the data binding object. To get a basic JavaScript object that represents the data binding, you can call toJSObject().