Using the Bindable metadata tag

When a property is the source of a data binding expression, Flex automatically copies the value of the source property to any destination property when the source property changes. To signal to Flex to perform the copy, you must use the [Bindable] metadata tag to register the property with Flex, and the source property must dispatch an event.

The [Bindable] metadata tag has the following syntax:

[Bindable] 
[Bindable(event="eventname")]

If you omit the event name, Flex automatically creates an event named propertyChange of type PropertyChangeEvent.

You can use the [Bindable] metadata tag in three places:

  1. Before a public class definition.

    The [Bindable] metadata tag makes usable as the source of a binding expression all public properties that you defined as variables, and all public properties that are defined by using both a setter and a getter method. In this case, [Bindable] takes no parameters, as the following example shows:

    [Bindable] 
    public class TextAreaFontControl extends TextArea {}

    The compiler automatically generates an event named propertyChange, of type PropertyChangeEvent, for all public properties so that the properties can be used as the source of a data binding expression.

    If the property value remains the same on a write, Flex does not dispatch the event or update the property, where not the same translates to the following test:

    (oldValue !== value)

    That means if a property contains a reference to an object, and that reference is modified to reference a different but equivalent object, the binding is triggered. If the property is not modified, but the object that it points to changes internally, the binding is not triggered.

    Note: When you use the [Bindable] metadata tag before a public class definition, it only applies to public properties; it does not apply to private or protected properties, or to properties defined in any other namespace. You must insert the [Bindable] metadata tag before a nonpublic property to make it usable as the source for a data binding expression.
  2. Before a public, protected, or private property defined as a variable to make that specific property support binding.

    The tag can have the following forms:

    [Bindable] 
    public var foo:String;

    The Flex compiler automatically generates an event named propertyChange, of type PropertyChangeEvent, for the property. If the property value remains the same on a write, Flex does not dispatch the event or update the property.

    You can also specify the event name, as the following example shows:

    [Bindable(event="fooChanged")] 
    public var foo:String;

    In this case, you are responsible for generating and dispatching the event, typically as part of some other method of your class. You can specify a [Bindable] tag that includes the event specification if you want to name the event, even when you already specified the [Bindable] tag at the class level.

  3. Before a public, protected, or private property defined by a getter or setter method.

    You must define both a setter and a getter method to use the [Bindable] tag with the property. If you define just a setter method, you create a write-only property that you cannot use as the source of a data-binding expression. If you define just a getter method, you create a read-only property that you can use as the source of a data-binding expression without inserting the [Bindable] metadata tag. This is similar to the way that you can use a variable, defined by using the const keyword, as the source for a data binding expression.

    The tag can have the following forms:

    [Bindable] 
    public function set shortNames(val:Boolean):void { 
        ...                 
    } 
     
    public function get shortNames():Boolean { 
        ... 
    }    

    The Flex compiler automatically generates an event named propertyChange, of type PropertyChangeEvent, for the property. If the property value remains the same on a write, Flex does not dispatch the event or update the property. To determine if the property value changes, Flex calls the getter method to obtain the current value of the property.

    You can specify the event name, as the following example shows:

    [Bindable(event="changeShortNames")] 
    public function set shortNames(val:Boolean):void { 
        ... 
        // Create and dispatch event.  
        dispatchEvent(new Event("changeShortNames")); 
    } 
     
    // Get method.  
    public function get shortNames():Boolean { 
        ... 
    }                

    In this case, you are responsible for generating and dispatching the event, typically in the setter method, and Flex does not check to see if the old value and the new value are different. You can specify a [Bindable] tag that includes the event specification to name the event, even when you already specified the [Bindable] tag at the class level.

The following example makes the maxFontSize and minFontSize properties that you defined as variables that can be used as the sources for data bindings:

    // Define public vars for tracking font size. 
    [Bindable] 
    public var maxFontSize:Number = 15; 
    [Bindable] 
    public var minFontSize:Number = 5;

In the following example, you make a public property that you defined by using a setter and a getter method that is usable as the source for data binding The [Bindable] metadata tag includes the name of the event broadcast by the setter method when the property changes:

    // Define private variable. 
    private var _maxFontSize:Number = 15; 
 
    [Bindable(event="maxFontSizeChanged")] 
    // Define public getter method. 
    public function get maxFontSize():Number { 
        return _maxFontSize; 
    } 
 
    // Define public setter method. 
    public function set maxFontSize(value:Number):void { 
        if (value <= 30) { 
            _maxFontSize = value; 
        } else _maxFontSize = 30; 
 
        // Create event object.  
        var eventObj:Event = new Event("maxFontSizeChanged"); 
        dispatchEvent(eventObj); 
 
    }

In this example, the setter updates the value of the property, and then creates and dispatches an event to invoke an update of the destination of the data binding.

In an MXML file, you can make all public properties that you defined as variables usable as the source for data binding by including the [Bindable] metadata tag in an <fx:Metadata> block, as the following example shows:

<fx:Metadata> 
    [Bindable] 
</fx:Metadata>

You can also use the [Bindable] metadata tag in an <fx:Script> block in an MXML file to make individual properties that you defined as variables usable as the source for a data binding expression. Alternatively, you can use the [Bindable] metadata tag with properties that you defined by using setter and getter methods.

Using read-only properties as the source for data binding

You can automatically use a read-only property defined by a getter method, which means no setter method, as the source for a data-binding expression. Flex performs the data binding once when the application starts.

Because the data binding from a read-only property occurs only once at application start up, you omit the [Bindable] metadata tag for the read-only property.

Using static properties as the source for data binding

You can use a static variable as the source for a data-binding expression. Flex performs the data binding once when the application starts, and again when the property changes.

You can automatically use a static constant as the source for a data-binding expression. Flex performs the data binding once when the application starts. Because the data binding occurs only once at application start up, you omit the [Bindable] metadata tag for the static constant. The following example uses a static constant as the source for a data-binding expression:

<?xml version="1.0"?>
<!-- binding/StaticBinding.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx">

    <fx:Script>
      <![CDATA[

        // This syntax casues a compiler error.
        // [Bindable]
        // public static var varString:String="A static var.";

        public static const constString:String="A static const.";
      ]]>
    </fx:Script>

    <!-- This binding occurs once at application startup. -->
    <s:Button label="{constString}"/>    
</s:Application>

The executing SWF file for the previous example is shown below:

Working with bindable property chains

When you specify a property as the source of a data binding expression, Flex monitors not only that property for changes, but also the chain of properties leading up to it. The entire chain of properties, including the source property, is called a bindable property chain. In the following example, firstName.text is a bindable property chain that includes both a firstName object and its text property:

<s:Label id="myText" text="{firstName.text}"/>

You can have a fairly long bindable property chain, as the following example shows:

<s:Label id="myText" text="{user.name.firstName.text}"/>

For the data binding mechanism to detect changes to the text property, only the text property has to be bindable. However, if you want to assign a new value to any part of the chain at runtime, every element in the chain must be bindable. Otherwise, modifying the user, name, or firstName property at runtime results in the data binding mechanism no longer being able to detect changes to the text property.

When using the BindingUtils.bindProperty() or BindingUtils.bindSetter() method, you specify the bindable property chain as an argument to the method. For example, the bindProperty() method has the following signature:

public static function bindProperty(site:Object, prop:String, host:Object, chain:Object, 
    commitOnly:Boolean = false):ChangeWatcher

The host and chain arguments specify the source of the data binding expression. You can define a data binding expression by using the bindProperty() method, as the following example shows:

bindProperty(myText, 'text', user, ["name","firstName","text"]);

In this example, ["name","firstName","text"] defines the bindable property chain relative to the user object. Notice that user is not part of the bindable property change in this example.

In an MXML data-binding expression, the bindable property chain is always relative to this. Therefore, to define a data binding equivalent to the MXML data binding expression shown above, you write the bindProperty() method as the following example shows:

bindProperty(myText, 'text', this, ["user", "name","firstName","text"]);