So You Think You Can Bind? – A Flex Puzzler
February 19th, 2009 Brian Gray, Consultant (email the author)
In my opinion, binding is one of the trickiest concepts for a Java developer to really understand when first learning Flex. It’s not because it is overly complex, but because binding is similar enough to other concepts in JSP, Swing, etc. that we begin to form mental models without fully understanding the differences. But those subtle differences are important for the last 20% of correctness in a lot of code.
The Puzzle
To illustrate, I cooked up a Java Puzzler-esque Binding puzzle. The application below contains a panel with a button on it. It has 2 states. Clicking the button switches to the ‘large’ state, at which point the panel widens and the button’s label changes to “Contract…” instead of “Expand….”
So go ahead and click the button, then see if you can answer this question: Why doesn’t the text change?
Source sample: (see link at end of post for full source)
<mx:states>
<mx:State name="large">
<mx:SetProperty target="{expandBtn}" name="label"
value="Contract the panel from width: {panel.width}" />
<mx:SetProperty target="{panel}" name="width" value="430"/>
</mx:State>
</mx:states>
<mx:Panel id="panel" width="330" title="Binding">
<mx:Button id="expandBtn"
label="Expand the panel from width: {panel.width}"
click="currentState='large'" />
</mx:Panel>
The Solution(s)
The answer is an explanation of what is really going on when you use the {} notation in mxml. When the MXML compiler sees a line like:
label="Expand the panel from width: {panel.width}"
it creates a binding. More importantly for this problem, it creates a ChangeWatcher, essentially telling Flex, “Any time that the width of the panel changes, call label’s setter using the updated value.” In this case, the updated value is “Expand the panel from width foo” where foo is the new width.
In most cases, this is exactly what the developer intends to happen. Complications arise when code elsewhere (either in an <mx:state> tag states as above or in scripts, other classes, other components, other bindings, etc.) also sets this same value. Why is this a problem? That ChangeWatcher that gets generated – it sticks around. The user clicks the button, the text of the label changes, but the original change watcher is still there. He’s still hanging out, listening to the panel width, and waiting to pounce.
Continuing the story, the panel width gets updated, and the change watcher from the original label springs into action. It wakes up and says, “Ah hah! My subject has changed, so I must update my bound value.” It sets the label to the only thing it knows to set it to, namely “Expand the panel from width foo.”
There are a couple ways to solve the problem that reveal some best practices dealing with binding in Flex. Here’s one I’ll talk about in a bit of detail:
The idea here is to not to change the label itself, since it’s going to have change watchers calling its setter. Using this new language of binding, you can think about this solution as follows. The label is now set to what is essentially a function with two parameters. One is the verb to be used (“Expand” or “Contract”) and the other is the width of the panel. This way, two change watchers are created, and any time either value changes, Flex will re-evaluate the expression and set the label text to the result.
Source sample: (see link at end of post for full source)
<mx:Script>
<![CDATA[
[Bindable]
public var verb:String = "Expand";
]]>
</mx:Script>
<mx:states>
<mx:State name="large">
<mx:SetProperty target="{this}" name="verb" value="Contract" />
<mx:SetProperty target="{panel}" name="width" value="430"/>
</mx:State>
</mx:states>
<mx:Panel id="panel" width="330" title="Binding">
<mx:Button id="expandBtn"
label="{verb} the panel from width: {panel.width}"
click="currentState='large'" />
</mx:Panel>
Another possibility is to do no binding at all. You could set the label when the button initializes based on the current width of the panel, and change it in the state itself since you know that’s when the panel also changes width.
The Lesson
The take-away here is the same in both solutions: know who is calling your setters. Generally, if you assign a value using the {} notation, that should be the only place that value gets set. Otherwise, you enter into a logic puzzle when an unexpected value appears – was it the change watcher from the generated binding, the ActionScript at the top of the MXML, other components accessing public properties, …?
Entry Filed under: Agile and Development
Pages
Categories
- Agile and Development
- Application Modernization
- Cloud Applications
- Process Integration
- Summa
- Technology + Healthcare
- Uncategorized
Most Recent Posts
- Summa Is Award Finalist at IBM’s Impact 2012
- Working with JqGrid and ASP.NET MVC - Setting up a base jqgrid parameters class
- Rebase a Slave Mercurial Repo to a Subversion Master
- The Social Enterprise Part 2 – How To Set Up Chatter In Less Than 30 Minutes
- Implement Clear Governance for BRMS
Feeds
Calendar
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « Jan | Mar » | |||||
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | |

1 Comment Add your own
1. James Ward | February 20th, 2009 at 2:39 pm
Cool puzzler! I’ve wanted to someday put together a Flex Puzzlers session like the Java Puzzlers one. If so, can I use this? (giving you credit of-course!)
-James
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed