Friday, February 10, 2012

Binding (Part 1)

This series like Event series is written in terms of questions and answers. I have prepared that after going through lot of blogs, documentation and interview questions.

So if you find this post helpful please comment. If you don't find it useful still provide you feedback about the stuff you would like to be improved/added? Please spend some time to provide your feedback that can help improve it.

Question: What is Binding/Data Binding? What are the different ways for binding?
Answer: Data binding is the process of tying the data in one object to another object. It provides a convenient way to pass data around in an application. There are mainly five main techniques for Data Binding:
1.     Using Braces with MXML tags.
2.     Using the fx:Binding tags.
3.     Using the BindingUtils class.
4.     Implicit and Explicit data binding.
5.     Custom Metadata.

Question: Describe main techniques for Data Binding?
Answer: These are as follow:
1. Using curly braces:  The text will be the value of slider.


<s:TextInput id="myTI" text="Enter text here"/> 

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



2. fx:Binding Tag: When using this tag, source and destination need to be provided. This tag completely separates view from Model in MVC architecture. It also allows specifying multiple sources for single destination, as we can have multiple tags for single destination.




<fx:Binding source="myTI.text" destination="myText.text"/> 

<s:TextInput id="myTI"/> 

<s:Label id="myText"/>






When using mxml tags for binding it (mxmlc compiler) generates a lot of code (generated actionscript files) that gets added to our application SWF.

3. Using Bindings in ActionScript: We can also define a binding in ActionScript by using the BindingUtils class. We used static BindingUtils.bindProperty() method to define the binding to bind a public property. We can also use the BindingUtils.bindSetter() method to define a binding to a setter function.
public static function bindProperty( site:Object, prop:String, host:Object, chain:Object, commitOnly:Boolean = false, useWeakReference:Boolean = false):ChangeWatcher
·         site: Represents the destination object.
·         host: Represents the source object.
·         commitOnly: Set to true in case the handler should be called only on committing change events; set to false in case the handler should be called on both committing and non-committing change events. Default is false.
·         useWeakReference: Allows you to decide whether the reference to the host is strong or weak. A strong reference (the default) prevents the host from being garbage collected. A weak reference does not.








<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"> 

  <s:layout> 

     <s:VerticalLayout/> 

  </s:layout> 

  <fx:Script> 

    <![CDATA[ 

       import mx.binding.utils.*; 

       public function initBindingHandler():void {

         BindingUtils.bindProperty(myText, "text", myTI, "text"); 

       } 

    ]]> 

  </fx:Script> 

  <s:TextInput id="myTI"/>

  <s:Label id="myText" preinitialize="initBindingHandler();"/>

</s:Application>






Notice in this example that you use the preinitialize event to define the data binding. This is necessary because Flex triggers all data bindings at application startup when the source object dispatches the initialize event.
The second static method is the bindSetter.
public static function bindSetter(setter:Function, host:Object,
chain:Object,
commitOnly:Boolean = false,
useWeakReference:Boolean = false):ChangeWatcher
·         setter: Bind a setter function to a bindable property or chain. Once the ChangeWatcher instance is successfully created, the setter function is invoked with the value or the chain object.
·         host: Represents the source object.
·         chain: Represents the property name.
·         commitOnly : Set to true in case the handler should be called only on committing change events; set to false in case the handler should be called on both committing and non-committing change events. Default is false.
·         useWeakReference: Allows you to decide whether the reference to the host is strong or weak. A strong reference (the default) prevents the host from being garbage collected. A weak reference does not.




<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/halo"

minWidth="1024" minHeight="768">

   <fx:Script>

      <![CDATA[

         import mx.binding.utils.BindingUtils;

         import mx.events.FlexEvent;

         protected function preinitializeHandler(event:FlexEvent):void

         {

            BindingUtils.bindSetter(bindingSetter, textInput, "text");

         }

         private function bindingSetter(str:String):void

         {

            label.text = str;

         }

     ]]>

   </fx:Script>

<s:layout>

  <s:VerticalLayout />

</s:layout>

  <s:TextInput id="textInput"  

               preinitialize="preinitializeHandler(event)" />

  <s:Label id="label" />

</s:Application>






Behind the scenes, the
ChangeWatcher class is used in the BindingUtils class to allow the usage of weak references, which means that you can set the weak reference to true and allow the host to be picked up by the garbage collector. This avoids any potential memory leaks. These two can be summarized in simple terms as:
BindingUtils.bindProperty(source, source-property, target, target-property);
BindingUtils.bindSetter(Setter function to be called, source, source-property);
Although we can use weak references, as we pointed out, the ChangeWatcher needs to be un-watched once we are complete and it’s our responsibility to handle that task which will ensure there are no memory leaks. The best way to handle this is to assign the static method to a ChangeWatcher variable.




<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"

minWidth="1024" minHeight="768">

   <fx:Script>

     <![CDATA[

        import mx.binding.utils.ChangeWatcher;

        import mx.binding.utils.BindingUtils;

        import mx.events.FlexEvent;

        private var change:ChangeWatcher;

        protected function preinitializeHandler(event:FlexEvent):void

        {

           change = BindingUtils.bindProperty( label, "text", 

                      textInput, "text");

        }

        protected function clickHandler(event:MouseEvent):void

        {

           change.unwatch();

           change = null;

        }

     ]]></fx:Script>

  <s:layout>

    <s:VerticalLayout />

  </s:layout>

  <s:TextInput id="textInput" 

     preinitialize="preinitializeHandler(event)" />

  <s:Label id="label" />

  <s:Button label="Stop binding" click="clickHandler(event)" />

</s:Application>





4.Implicit Binding and Explicit Binding: The main difference Implicit Binding and Explicit Binding is that implicit binding is done at runtime where as explicit binding is done at compile time. As an example of implicit binding we will be using an implicit getter and setter.





public class ClassA extends UIComponent

{

    private var _value:Number;

    [Bindable]

    public function get value():Number

    {

       return _value;

    }

    public function set value(num:Number):void

    {

       _value = num;

    }

}





Here a propertyChangeHandler event is dispatched by default. We can specify our own custom event also if we want.




[Bindable(event="valueWasChanged")]

public function get value():Number

{

return _value;

}

public function set value(num:Number):void

{

_value = num;

var eventObj:Event = new Event("valueWasChanged");

dispatchEvent(eventObj);

}





A minimal example of explicit binding is:




<fx:Script>

   <![CDATA[

      [Bindable]

      private var num:Number = 5;

      private function init(num:Number):void

      {

          this.num = num;

      }

    ]]>

</fx:Script>






There can be times when binding classes are using try/catch blocks and exception thrown are silently captured, in these case we like to know whether binding was actually triggered or not.





<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"

minWidth="1024" minHeight="768" creationComplete="creationCompleteHandler(event)">

  <fx:Script>

    <![CDATA[

       import mx.events.FlexEvent;

       [Bindable]

       public var value:String = "Hello World";

       protected function creationCompleteHandler(event:FlexEvent):void

       {

            BindingManager.debugBinding("label.text");

       }

   ]]></fx:Script>

<s:layout>

  <s:VerticalLayout />

</s:layout>

<s:TextInput id="textInput" change="{value=textInput.text}" />

<s:Label id="label" text="{value}" />

</s:Application>






We have seen that lots of Binding tags can be a bottleneck for the application performance. The alternative is to use ChangeWatcher and BindingUtils classes, but these require management to avoid memory leaks. So a better way is to use [TurboBinding] tag explained later.

Question: When data binding occurs?
Answer: Data binding occurs in following cases –
  1. The binding source dispatches an event because the source has been modified.
  2. At application startup when the source-object dispatches the initialize event all data binding are triggered once at application startup to initialize the destination property.
The executeBindings() method of UIComponent executes all the bindings for which a UIComponent is destination. The executeChildBindings() method of the Container and Repeater classes executes all of the bindings for which the child UIComponent components of a Container or Repeater class are destinations. All containers extend the Container class. These methods give us a way to execute bindings that do not occur as expected. By adding one line of code, such as a call to the executeChildBindings() method, we can update the user interface after making a change that does not cause bindings to execute. However, we should only use the executeBindings() method when we are sure that bindings do not execute automatically.

Question: What properties support Data Binding?
Answer: We can use all properties of an object as the destination of a data binding expression. However, to use a property as the source of a data binding expression, the source object must be implemented to support data binding, which means that the object dispatches an event when the value of the property changes to trigger the binding. A property that can be used as the source of a data-binding expression is referred to as a bindable property.
Using read-only properties as the source for data binding
We can 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.
Using static properties as the source for data binding
We can automatically use a static constant as the source for a data-binding expression. Flex performs the data binding once when the application starts. We can use a static variable as the source for a data-binding expression. Flex performs the data binding once when the application starts.
Creating properties to use as the source for data binding
When we create a property to use as source of data binding,Flex can automatically copy the value of source to any destination property when source changes. To signal to flex to perform the copy, property must be registered with [Bindbable] tag.
[Bindable]
[Bindable (event = “eventName”)];

We can omit the event keyword and specify the tag as
[Bindable (“eventName”)];

If we omit the event name Flex creates an event named propertyChange of type PropertyChangeEvent and dispatches that when the property changes to trigger any data bindings that use the property as a data-binding source. If we specify event name then it is our responsibility to dispatch the event when the source property changes.

Question: Give an example of using data binding with data models.
Answer:







<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"> <s:layout> 

   <s:VerticalLayout/> 

</s:layout> 

<fx:Declarations>

      <!-- Data model stores registration data that user enters. -->

     <fx:Model id="reg"> 

          <registration> 

               <name>{fullname.text}</name> 

               <email>{email.text}</email>

           </registration> 

     </fx:Model>

 </fx:Declarations> 




<mx:Form> 

   <mx:FormItem label="Name" required="true"> 

        <s:TextInput id="fullname" width="200"/>

   </mx:FormItem>

   <mx:FormItem label="Email" required="true"> 

         <s:TextInput id="email" width="200"/>

    </mx:FormItem> 

</mx:Form>

</s:Application>







Question: Give an example of binding a source to more than one destination properties.
Answer: We can bind a single source property to more than one destination property by using the curly braces ({}) syntax, the tag, or the BindingUtilsmethods in ActionScript.







<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">

 <s:layout> 

    <s:VerticalLayout/>

 </s:layout> 

<fx:Declarations> 

   <fx:Model id="mod1"> 

     <data> 

      <part>{input1.text}</part>

     </data> 

  </fx:Model> 

  <fx:Model id="mod2"> 

    <data> <part>{input1.text}</part> 

    </data> 

  </fx:Model> 

</fx:Declarations>

<s:TextInput id="input1" text="Hello" />

<s:Label text="{mod1.part}"/>

<s:Label text="{mod2.part}"/>

</s:Application>






Question: Give an example of binding more than one source to one destination property.
Answer: This one is tricky.







<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">

 <s:layout>

   <s:VerticalLayout/>

 </s:layout>

 <fx:Binding source="input2.text" destination="myTA.text"/>      

 <s:TextInput id="input1"/> 

 <s:TextInput id="input2"/>

 <s:TextArea id="myTA" text="{input1.text}"/>

</s:Application>




Second Part

10 comments:

Anonymous said...

I simply liked it.

FlexPost said...

Good Post congratulation...

FlexPost said...

good post keep doing it...

Anonymous said...

Great stuff!

Akhil Mittal said...

Thanks guys!!

Hunny said...

Akhil, Great job. I never find such good stuff for flex interview preparation.
Need a favor , Could you please post some questions about Flex Life cycle also.

Roudranil Roy said...

very useful. thanks

Anonymous said...

Nice post on Binding, keep up the good work.

Monik said...

Very Useful. Thanks Akhil.

Anonymous said...

One stop for all the questions. Nice collection. Great work buddy.. :)