Sunday, March 23, 2008

Darren on Flex: Binding Expression Clash With HTML Entity-Reference Delimeter

You fellow Flex programmers should know all about the handy binding notation provided as a language construct in MXML. For those that don't know, it makes short work of event-wiring; forget implementing interfaces and defining handlers - just bind it. With binding in mind, recently I tried to bind to the AND logical result but received an error in FB3. This highlights a feature of MXML, that is, the overlap of the symbol/name/token/something-space of embedded AS code and that of HTML/XML. To be clear, I am no talking about (instance) variable namespaces or scopes, Flex handles this seamlessly; what I am talking about is the names for constructs (or maybe it's syntax tokens) in those respective languages. For example see the following code:
<application mx="http://www.adobe.com/2006/mxml" model="com.zuhlke.tutorial.hibernate.model.*" creationcomplete="eventDS.fill(events, 'all.events', [])" layout="vertical">

...

</application>
In this snippet we routinely assign an expression, in this case a function call, to be evaluated in response to the creationComplete event. Notice that to pass a String (i.e. 'all.events') as an argument we have to switch between quoting characters to maintain valid XML - not adding anything new here, this trick is age old. The following example demonstrates what I was trying to do, as described above:
<mx:TextInput id="eventTitle" width="100%" />
<mx:DateField id="eventDate" width="100%" />
...

<mx:Button id="add"  label="Add..." enabled="{eventTitle.text != '' && eventDate.text != ''}" click="addHandler()" />
This code will not compile in FB3 as the && ie. logical AND operator in the binding expression for the Button.enabled property clash with the entity-reference language construct for XML notation. So with knowledge converting between different logical expressions in the same equivalance class, we can re-write the binding expression such that the compiler is kept happy:
<mx:TextInput id="eventTitle" width="100%" />
<mx:DateField id="eventDate" width="100%" />
...

<mx:Button id="add"  label="Add..." enabled="{!(eventTitle.text == '' || eventDate.text == '')}" click="addHandler()" />
Now this is really a matter of taste; you can of course use the following instead:
<mx:TextInput id="eventTitle" width="100%" />
<mx:DateField id="eventDate" width="100%" />
...

<mx:Button id="add"  label="Add..." enabled="{isEnabled(eventTitle.text, eventDate.text)}" click="addHandler()" />
where a function with the signature isEnabled(title:String, date:String):Boolean does the job. Note: it seemed necessary to pass in the text properties of the TextInput and DateField components, I suspect because these are bindable properties, where the components themselves (in their context) perhaps are not.

2 comments:

Immo Hüneke said...

Could you just have expressed the && operator as &amp;&amp;?

Darren Bishop said...

It didn't occur to me that that solution might work, given that it is not valid ActionScript, however I just tried it and it did.

The error message prompts for a 'proper' entity reference when it encounters the && token, which should have been a clue.

Cheers