Friday, February 10, 2012

Binding (Part 2)


Question: How to use bi-directional binding.
Answer:  We can define a bidirectional data binding using one of the following methods:
1. Define two objects that specify as the source a property of the other object. In the following example, input1 specifies input2.text as the source property, and input2 specifies input1.text as the source property. Any change to input1.text updates input2.text, and any change to input2.text updates input1.text:




<!-- Specify data binding for both controls. --> 

<s:TextInput id="input1" text="{input2.text}"/> 

<s:TextInput id="input2" text="{input1.text}"/>





 2. Use the @{bindable_property} syntax for one source property, as the following example shows:




<!-- Specify data binding for both controls. -->

 <s:TextInput id="input1" text="@{input2.text}"/>

 <s:TextInput id="input2"/>




Note: The property definition that includes the @{bindable_property} syntax i s called the primary property. If the primary property has not had a value assigned to it, the binding to it occurs first, before a binding to the other property.
3. Use the twoWay property of the tag, as the following example shows:


<fx:Binding source="input1.text" destination="input2.text" twoWay="true”/>


Because both the source and the destination properties must resolve to a bindable property or property chain at compile time, neither property value can include a binding expression.







<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 paddingTop="10"/>

 </s:layout>

 <s:Label text="Specify data binding for both controls."/>

 <s:TextInput id="input1" text="{input2.text}"/>

 <s:TextInput id="input2" text="{input1.text}"/>

 <s:Label text="Use the bidirectional data binding syntax."/>

 <s:TextInput id="input3" text="@{input4.text}"/>

 <s:TextInput id="input4"/> 

 <s:Label text="Use the Binding tag."/> 

 <s:TextInput id="input5"/> 

 <s:TextInput id="input6"/> 

 <fx:Binding source="input5.text" destination="input6.text"  twoWay="true"/>

</s:Application>






Though bi-directional binding is supported at most of the places, it is not supported at the following places.
Expression
Binding Supported
Style Properties
No
Effect Properties
No
The request property of the HttpService, RemoteObject and WebService class
No
The arguments property of the RemoteObject class.
No

Question: Give example of using functions as the source for a data binding.
Answer: Two common techniques with functions are to use bindable properties as arguments to the function to trigger the function, or to trigger the function in response to a binding event.
Using functions that take bindable properties as arguments




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

   <mx:CurrencyFormatter id="usdFormatter" precision="2"  currencySymbol="$" alignSymbol="left"/> 

</fx:Declarations>

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

 <s:TextArea text="{usdFormatter.format(myTI.text)}"/> 

</s:Application>





In this example, Flex calls the CurrencyFormatter.format() method to update the TextArea control every time the text property of the TextInput control is modified.

Binding to functions in response to a data-binding event








<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 flash.events.Event; // Define a function that gets invoked 

   // in response to the myFlagChanged event. 

   [Bindable(event="myFlagChanged")] 

   private function isEnabled():String 

   { 

     if (myFlag)

        return 'true'; 

     else 

        return 'false'; 

   }

   private var _myFlag:Boolean = false; 

   // Define a setter method that dispatches the 

   // myFlagChanged event to trigger the data binding. 

   public function set myFlag(value:Boolean):void { 

    _myFlag = value; 

    dispatchEvent(new Event("myFlagChanged")); 

  }

  public function get myFlag():Boolean { 

   return _myFlag; 

  }

  ]]> 

 </fx:Script> 

 <!-- Use the function as the source of a data binding expression. -->  

 <s:TextArea id="myTA" text="{isEnabled()}"/>

 <!-- Modify the property, causing the setter method to dispatch the 

 myFlagChanged event to trigger data binding. --> 

 <s:Button label="Clear MyFlag" click="myFlag=false;"/> 

 <s:Button label="Set MyFlag" click="myFlag=true;"/>

</s:Application>





We use the [Bindable] metadata tag to specify to Flex to invoke the isEnabled()function in response to the event myFlagChanged. When the myFlag setter gets called, it dispatches the myFlagChanged event to trigger any data bindings that use the isEnabled()function as the source:

Question: Give example of using data binding with objects.
Answer: There is a difference between binding to an object or binding to properties of an object.
Binding to Objects




package myComponents



  public class NonBindableObject extends Object {

      public function NonBindableObject() { super(); }

      public var stringProp:String = "String property"; 

      public var intProp:int = 52; 

  }

}




<!-- binding/WholeObjectBinding.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" creationComplete="initObj();"> 

 <s:layout>

   <s:VerticalLayout/>

 </s:layout>

 <fx:Script>

  <![CDATA[ 

   import myComponents.NonBindableObject; 

   [Bindable] 

   public var myObj:NonBindableObject = new NonBindableObject(); 

   [Bindable] 

   public var anotherObj:NonBindableObject = new NonBindableObject(); 

   public function initObj():void { 

     anotherObj.stringProp = 'anotherObject';

     anotherObj.intProp = 8; 

   }

  ]]>

 </fx:Script> 

 <!-- Data binding updated at application startup. --> 

 <s:Label id="text1" text="{myObj.stringProp}"/> 

 <!-- Data binding updated at application startup. --> 

 <s:Label id="text2" text="{myObj.intProp}"/> 




 <!-- Data bindings to stringProp not updated. --> 

 <s:Button label="Change myObj.stringProp" 

  click="myObj.stringProp = 'new string';"/> 

 <!-- Data bindings to intProp not updated. --> 

 <s:Button label="Change myObj.intProp" click="myObj.intProp = 10;"/> 




 <!-- Data bindings to myObj and to myObj properties updated. -->   

 <s:Button label="Change myObj" 

  click="myObj = anotherObj;"/>

</s:Application>






Binding to properties of Objects







package myComponents{

 // binding/myComponents/BindableObject.as 

 // Make all class properties bindable. 

  [Bindable] 

  public class BindableObject extends Object { 

     public function BindableObject() { super(); } 

     public var stringProp:String = "String property"; 

     public var intProp:int = 52; 

  }

}




//Main Changes

<!-- Data bindings to stringProp updated. --> 

<s:Button label="Change myObj.stringProp" 

click="myObj.stringProp = 'new string';"/> 

<!-- Data bindings to intProp updated. --> 

<s:Button label="Change myObj.intProp" click="myObj.intProp = 10;"/> <!-- Data bindings to myObj and to myObj properties updated. --> <s:Button label="Change myObj" click="myObj = anotherObj;"/>






Question: Give example of using data binding with array.
Answer: When working with arrays, such as Array or ArrayCollection objects, we can define the array as source or destination of binding expression.
Note: When defining a data binding expression that uses an array as the source of a data binding expression, the array should be of type ArrayCollection because the ArrayCollection class dispatches an event when the array or the array elements change to trigger data binding. For example, a call to ArrayCollection.addItem(), ArrayCollection.addItemAt(), ArrayCollection.removeItem(), and ArrayCollection.removeItemAt() all trigger data binding.

Binding to arrays








<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.collections.ArrayCollection; 

    [Bindable] 

    public var myAC:ArrayCollection = new ArrayCollection([ "One", 

    "Two", "Three", "Four"]); 

   ]]> 

 </fx:Script> 

 <!-- Data binding updated at application startup, when myAC is  

 modified, and when an element of myAC is modifed. --> 

 <s:List width="150" dataProvider="{myAC}"/> 

 <!-- Data bindings to myAC updated. --> 

 <s:Button label="Change Element" click="myAC[0]='mod One'"/> 

 <!-- Data bindings to myAC updated. -->

 <s:Button label="Add Element" click="myAC.addItem('new element');"/>

</s:Application>






Binding to array elements
We can define individual array element as source and destination for binding expression.







<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.collections.ArrayCollection;

      [Bindable] 

      public var myAC:ArrayCollection = new ArrayCollection([ "One", 

      "Two", "Three", "Four"]); 

      [Bindable] 

      public var myAC2:ArrayCollection = new ArrayCollection([ "Uno", 

      "Dos", "Tres", "Quatro"]); ]]> 

  </fx:Script>

  <!-- Data binding updated at application startup and when myAC 

  modified. --> 

  <s:Label id="text1" text="{myAC[0]}"/> 

  <!-- Data binding updated at application startup, when myAC modified, 

  and when myAC[0] modified. --> 

  <s:Label id="text2" text="{myAC.getItemAt(0)}"/> 

  <s:Button id="button1" label="Change Element" 

   click="myAC[0]='new One'"/> 

  <s:Button id="button2" label="Change ArrayCollection"   

   click="myAC=myAC2"/>

</s:Application>





If you specify an array element as the source of a data binding expression by using the square bracket syntax, [], data binding is only triggered when the application starts and when the array or a reference to the array is updated; data binding is not triggered when the individual array element is updated. The compiler issues a warning in this situation. However, the data binding expression myAC.getItemAt(0) is triggered when an array element changes. Therefore, the text2 Text control is updated when we click button1, while text1 is not. When using an array element as the source of a data binding expression, you should use the ArrayCollection.getItemAt() method in the binding expression. Clicking button2 copies myAC2 to myAC, and triggers all data bindings to array elements regardless of how you implemented them.

Question: What are the difference between binding at compile time (using mxml) and binding at runtime (using Action script)?
Answer: 1. We cant use any action script code in bindProperty or bindSetter() method. Instead bindSetter() specify a method to call when binding occurs.
2. We cannot include an E4X expression in data binding expression in AS.
3. We cannot include functions or array elements in property chains in a data binding expressions
defined by bindProperty() or bindSetter() method.
4. MXML compiler has better warning and error detection support than runtime data binding by
these methods.

Third Part

2 comments:

Jameel Ahmad said...

Wahh Mittal ji..kamal ka kaam kiya hai. Hats off to you bro..keep up good work.

Akhil Mittal said...

Thanks Jameel and sorry for late response.