How many times have you had to bind some visual object to more than one property? Many times we have to show, for example, a label with the full name that depends on the First name and the second name, or maybe we need a getFullAdress() method that returns the house number, street, city, postcode and country...
When we come across this problem we tend to do the following:
private function getFullName() : String
{
return firstName + familyName;
}
.....
<mx:Label text="Your name is: { getFullName() }"/>
However, this will not work as desired; if we change the firstName or the familyName property, the binding events will not be dispatched and our Label object will not be updated with the new values.
Our next thought will be to use the following code:
private function getFullName( first : String, family : String ) : String
{
return firstName + familyName;
}
.....
<mx:Label text="Your name is: { getFullName( firstName, familyName) }"/>
This will work as we whant, but it doesn´t have a good performance as it will trigger too many events for doing what we need.
There is a much better way of doing the same thing (and more elegant also!) which consists on making the function Bindable and assign an event to it, then, we can dispatch that event whenever any of the values invoved change and all the function listeners will automaticaly be updated.
Here we can see a very simple example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" height="240" width="320" layout="absolute">
<mx:Script>
<![CDATA[
[Bindable]
private var _firstName : String = "";
[Bindable]
private var _familyName : String = "";
[Bindable("nameChanged")]
public function getFullName() : String
{
return _firstName + " " + _familyName;
}
public function set firstName( value : String ) : void
{
_firstName = value;
dispatchEvent( new Event( "nameChanged" ) );
}
public function set familyName( value : String ) : void
{
_familyName = value;
dispatchEvent( new Event( "nameChanged" ) );
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem>
<mx:Label text="First Name:"/>
<mx:TextInput id="txtFirstName" change="firstName = txtFirstName.text"/>
</mx:FormItem>
<mx:FormItem>
<mx:Label text="Family Name:"/>
<mx:TextInput id="txtFamilyName" change="familyName = txtFamilyName.text"/>
</mx:FormItem>
<mx:Label text="Your name is: { getFullName() }"/>
</mx:Form>
</mx:Application>
And here you can see the example running:
Hope it helps :)
I'm glad you talk about this issue, because one month ago, I tried to make this kind of binding:
ReplyDelete< mx:Binding source="getFullName( firstName, familyName)" destination="fullName"/>
Instead of MXML, AS3, ¿do you know the way to make this using BindingUtils class?
Hello Jose Ignacio, there is a way of doing it with a (tiny) hack, it consists on creating a mock variable just with a getter method, assign the event handled to it like this:
ReplyDelete[Bindable("nameChanged")]
public function get bindToThis () : String
{
return getFullName();
}
Keep the rest of the code as shown on the code, except for the [Bindable] declaration on getFullName(), that won't exist now:
public function getFullName() : String
{
return _firstName + " " + _familyName;
}
public function set firstName( value : String ) : void
{
_firstName = value;
dispatchEvent( new Event( "nameChanged" ) );
}
public function set familyName( value : String ) : void
{
_familyName = value;
dispatchEvent( new Event( "nameChanged" ) );
}
Your view would be just declared like this:
< mx:Label id="txt"/>
And now you can assign the binding on the creationComplete of you component or wherever you need using the following line of code:
BindingUtils.bindProperty( txt, "text", this, "bindToThis");
This will have the same behaviour we had before.
Hope it helps :)