PSA: Bindable Setters Don’t Fire!

13 12 2006

I ran into a strange problem in Flex yesterday, and I wanted to share it with you in an effort to make the world a better place. I found that some logic in a setter on my model wasn’t getting executed, which was quite confusing.

First of all, getters/setters are a set of functions in Actionscript (since version 2) that allow you to syntactically treat a function like a property, e.g.:

objectWithoutGetterSetter.setValue(42);
val =
objectWithoutGetterSetter.getValue(); //val=42;
objectWithGetterSetter.value = 42;
val =
objectWithGetterSetter.value; //val=42
// on ObjectWithGetter
public function set value(val:int):void {
this.val = val;
}
public function get value():int {
return this.val;
}

The benefit is readability, mostly, which is all to the good. To the world outside the object it looks like it has a property. In the getter and setter I can execute logic like in a traditional function.

There is another feature of Actionscript, Binding, that works particularly well with getters/setters. It allows me to annotate a setter as “bindable” using the [Bindable] annotation. Elsewhere in the code I can use certain language features to “bind” to that variable, getting changes automagically.

The problem is when I mark a getter/setter pair [Bindable] (works on either the getter or setter) the binding logic decides that if I call the setter with the value that the getter returns (i.e. the current value) the logic in the setter will not execute. IMHO, this breaks the setter pattern. What use is it to have a cool feature like a setter if you can’t depend on the logic in it? You may as well only bind to a traditional property and change that property through a traditional setter function.

I assume the code works the way it does because of performance: Having the whole binding chain execute when the value didn’t change may be inefficient. Perhaps there’re other reasons. Still, it’d be nice to have this behavior explicit, since I may have important logic that needs to execute even if the value doesn’t actually change. I may not know, and I certainly don’t want to have to check each time.

Forewarned is fore-armed and all that. Watch out for bindable getter/setter pairs.

Advertisements

Actions

Information

6 responses

23 04 2007
ericsoco

ack. spent the whole afternoon on this problem. it’s definitely a bug IMHO; ‘bug’ may not be exactly the right word, perhaps it’s better to say “bad design decision” on the part of Adobe.

take, for example, a setter that is expecting an Array. i set the array property to arrayX; the setter fires. i modify arrayX — for example, i push something into it — and again set the array property to arrayX. the setter doesn’t fire, the display that’s binding that array property doesn’t update.

not good.

13 07 2007
Luke Bayes

It’s actually even worse if your properties contain references to objects rather than simply primitive values.

If someone changed a value on the object, and then calls the setter hoping to trigger an update, none will come. You have to first set it to null, then re-set the reference.

Kind of frustrating, but probably not as frustrating as an extremely slow, choppy experience….

10 12 2007
mika

Thanks for information.

15 04 2008
Ryan Bell

I’m glad you documented this. I just ran into this today here down the block in a setter that wasn’t causing a component to update itself as expected. My workaround: make a public “refresh()” method on the component, and move all update logic from the setter to that method. Then in addition to having the setter call refresh(), I call it externally if the property is already set to the object reference I want it to use. There are probably more elegant ways of doing this but it works…

17 04 2008
Ryan Bell

Maybe you figured this out already, but I just found another (perhaps better) workaround for this as I was reading Adobe’s Flex Binding documentation.

Supposedly, if you specify a custom binding event instead of letting Flex manage it by generating its own propertyChange event, it will skip the check to to see if the new value matches the current value, and will call the setter regardless. The setter would then be responsible for determining if a change really had occurred and dispatching the custom binding event itself.

[Bindable(event=”myPropChange”)]

23 07 2008
nwebb » One Reason Why Your Flex Getter May Not Execute

[…] ensures that the setter is run regardless. The issue was also reported by Tony Hillerson ( thanks to Tony and the guys who left comments for identifying the cause and saving me from […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: