Thursday, October 16, 2008

BindingUtils Example

I am working on an application which is not architect properly. So, I need to find solutions which just keeps things going. I have an illustration below for your reference:
image
Say, I have 3 custom components on my screen namely:
  • Component 1
  • Component 2
  • Component 3
Requirement is:
For Component 1:
Whenever some specific property changes in Component 1, it should be reflected in Component 3.
Whenever some properties in Component 2 changes, Component 1 should reflect those values.

For Component 2:
Nothing, It could just work independently

For Component 3:
It can work independently but it has to display updates from Component 1 and Component 2.
Problem:
As I mentioned there is no Framework used and application is not architect so I used Binding for rescue. (You can do it by passing values in a CustomEvent and passing those values from one component to other component, I guess BindingUtils do the same.)

Below is a sample code:
BindingUtilsExample.mxml
<?xml version="1.0" encoding="utf-8"?>


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCC()">


<mx:Script>


<![CDATA[


import mx.binding.utils.BindingUtils;


import mx.controls.Alert;
[Bindable]
public var ds:DataSingleton = DataSingleton.getInstance();

/**
  * called on creation complete to bind my textinput to my data
  */
public function onCC():void{
BindingUtils.bindProperty(myTxtInput,"text", ds,"data");
}

/**
  * Every time I click on button, I update values in my model (Simply a +1 that too string
  */
public function onClick():void{
if(ds.data != null )
{
ds.data += " 1";
}else{
ds.data = "some value";
} 

//Alert.show(ds.data);
}
]]>
</mx:Script>
<mx:VBox height="100%" width="100%">
<mx:HBox width="100%" height="100%">
<mx:Panel title="Component 1" height="100%" width="100%">
<mx:TextInput id="myTxtInput" text="This will have binding from my model"  width="100%"/>
</mx:Panel>
</mx:HBox>
<mx:HBox width="100%" height="100%">
<mx:Panel title="Component 2" height="100%" width="100%">
<mx:Label text="Click on button to update model value"/>
<mx:Button label="Click me" click="onClick()" />
</mx:Panel>
</mx:HBox>
</mx:VBox>
</mx:Application>
DataSingleton.as
package {
public class DataSingleton {
/**
  * Single instance which will exist throughout the app
  * for this class
  */
private static var instance:DataSingleton;
/**
  * Flag to check wheather instance already exist or not
  */
private static var allowInstantiation:Boolean;
/**
  * Data which I want to share across components
  */
private var _data:String;
/**
  * Method to get the instance of this class
  */
public static function getInstance():DataSingleton {
if (instance == null) {
allowInstantiation = true;
instance = new DataSingleton();
allowInstantiation = false;
}
return instance;
}
/**
  * Constructor
  * Checks if instance already exists then throw an error
  */
public function DataSingleton():void {
if (!allowInstantiation) {
throw new Error("Error: Its a Singleton Class. Use DataSingleton.getInstance() to instantiate.");
}
}
[Bindable]
/**
  * Make getter method of your data [Bindable] to make BindingUtils to get these values
  */
public function get data():String{
return this._data;
}
/**
  * Setter for my data to share across
  * Call this method in one of your component to update it and let BindingUtils update it for you 
  * in some other component
  */
public function set data(value:String):void{
this._data = value;
}
}
}

Here is what I have done:
  1. Create a Singleton Class
  2. Defining the properties you want to bind and share across different Components
  3. Make the getter of that property [Bindable]
    e.g.:


    [Bindable]
    //Make getter method of your data [Bindable] to make BindingUtils to
    //get these value
      public function get data():String{
          return this._data;
      }

  4. On creationComplete event (this is specific to my case, may be you need to find when it is suitable for you to bind, as when all components get ready)

    BindingUtils.bindProperty(myTxtInput,"text", ds,"data");

    I have one text input in my example which needs to be updated on click of a Button in some other component. Click of button, basically updates property of my singleton class. Here is a description for arguments provided in bindProperty method:






    1. myTxtInput: Object which you want to update
    2. text: Object's property which will get the value (In my case its a textinput text property)
    3. ds: Object from where you which you will get the value
    4. data: property which needs to be assigned. (Right side argument)


One more finding (Setting dataProvider in actionscript 3):

In MXML, I used to write something like

public var myArrayCollection:ArrayCollection = new ArrayCollection();

<mx:SomeComponent id="myComponent" dataProvider={myArrayCollection} ..... />

To set dataProvider in actionscript and binding it, equivalent to above is:

BindingUtils.bindProperty(myComponent,"dataProvider", this,"myArrayCollection");

To see sample example Click here.