Saturday, May 26, 2012

Flex: [Bindable] getter and setter issue on value re-setting

Hello.

Flex has one interesting trap (or trick, whatever word you like) with metatag [Bindable].

The issue is next: when we put Bindable on getter function, setter will automatically check the incoming value on uniqueness.

Let's take a look on the example below:
there are two properties, one of them has Bindable on getter and another one has not.
Their setters invoke trace() functions which show setter name and incoming value.
And method test() which assigns the same string three times per each property.

            //------------------------------
            // property1
            //------------------------------
            
            private var _property1:String;
            
            public function get property1():String
            {
                return _property1;
            }

            public function set property1(value:String):void
            {
                _property1 = value;
                
                trace("set property1=" + value);
            }

            //------------------------------
            // property2
            //------------------------------
            
            private var _property2:String;
            
            [Bindable]
            public function get property2():String
            {
                return _property2;
            }

            public function set property2(value:String):void
            {
                _property2 = value;
                
                trace("set property2=" + value);
            }
            
            private function test():void
            {
                property1 = "label1";
                property1 = "label1";
                property1 = "label1";
                
                property2 = "label2";
                property2 = "label2";
                property2 = "label2";
            }

After test() execution, you will see next output:


set property1=label1
set property1=label1
set property1=label1
set property2=label2

As you can see, the second property has assigned the 'label2' only once, because its getter has metatag Bindable.
In other words, setter does the verification - is property equal or not. If it is different, then the value will be re-set. Yes, very usefull and no need to write extra verification code.

But the trap is that this verification is done on instance reference level.

Let's take a look on the next example:

            //------------------------------
            // property3
            //------------------------------
            
            private var _property3:Object;
            
            [Bindable]
            public function get property3():Object
            {
                return _property3;
            }
            
            public function set property3(value:Object):void
            {
                _property3 = value;
                
                trace("set property3: value.field1=" + value.field1);
            }
            
            private function test():void
            {
                var obj:Object = {};
                obj.field1 = "primary test value";
                property3 = obj;
                
                obj.field1 = "secondary test value";
                property3 = obj;
            }


The output is:

set property3: value.field1=primary test value


Object was set only once, setter's trace was not executed second time because reference of the object was the same. This is logically from Flex side. But if outer code is binded to this getter 'property3' and uses 'field1' for some purposes, it (outer code) will not 'listen' that 'field1' was updated.


Another example: in the end of setter, some event is dispatched. On simple object resetting, you expect this event to be dispatched, however if the reference to the object is the same, setter will not dispatch this event again.

The moral of this topic is short - be carefull using bindable properties with extra logic in setters.