Some recent comments by a JavaScript developer made me consider Flex programming in a new light. Many web developers follow a best practice of always separating their content, styles, and scripts into distinct parts. An HTML document should contain only the structured content of the document. CSS and JavaScript files should be loaded from external sources. As a Flex developer, you have similar building blocks at your disposal. MXML contains the structure of your application, stylesheets modify the application’s appearance, and ActionScript 3 lets you interact with the application’s components. Style
and Script
elements can load their respective content from other sources when you compile your application. Certainly, Flex developers can benefit from the practice of separating these three parts.
Let’s start out by defining a very simple Flex application. It contains a Button
component with blue text that traces some text to the console when a user clicks it with their mouse. Nothing special, but it should help us explore the possibilities.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Button label="Click Me!" click="trace('You clicked the button!');" color="#0000ff"/> </mx:Application>
It’s only three lines of code, and that’s pretty cool. On the other hand, everything appears all mixed together in the MXML. There’s nothing wrong with that code, but let’s explore some possibilities for separation. Consider this more complex version that puts the ActionScript and a styles into their own tags.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Button label="Click Me!" click="clickHandler(event)"/> <mx:Script> import flash.events.MouseEvent; private function clickHandler(event:MouseEvent):void { trace("You clicked the button!"); } </mx:Script> <mx:Style> Button {color: #0000ff;} </mx:Style> </mx:Application>
The majority of MXML files in complex Flex applications will probably look like that. Events will be sent to ActionScript functions and styles will all be defined in one central location. These two items could easily be loaded from external files:
<mx:Script source="myApplicationCode.as"/> <mx:Style source="myApplicationStyles.css"/>
Surely, that’s separation nirvana… or is it? 😉
The JavaScript developer that I spoke with wondered why you need to call an ActionScript function within the MXML when listening for the click event. That’s a bad thing to do when working with HTML. Visitors with browsers that don’t have JavaScript, or users that turn it off, have trouble when a webpage calls JavaScript functions directly in hyperlinks. Can Flex achieve a stronger separation? Yes, actually it can. Should it? Probably not, but it’s a fun exercise. Consider the following revisions:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Button id="myButton" label="Click Me!"/> <mx:Script> import flash.events.MouseEvent; override protected function initializationComplete():void { super.initializationComplete(); this.myButton.addEventListener(MouseEvent.CLICK, clickHandler); } private function buttonClickHandler(event:MouseEvent):void { trace("You clicked the button!"); } </mx:Script> <mx:Style> Button {color: #0000ff;} </mx:Style> </mx:Application>
As you can see, we’ve overridden the initializationComplete
function to listen for the button’s click event. Now, every line of ActionScript appears inside the Script element. Pretty cool, don’t you think?
Remember, I’m not advocating that everyone go to these lengths to keep scripting, style, and structure apart. It’s far more important in the JavaScript world, but I believe that any developer can learn and grow by studying how other programmers do things–especially those that use different languages. You also shouldn’t over-architect your applications. I’d say that the first example with three lines of code would be the right way to build the example, but such a simple example lets us explore interesting concepts without needing to think about what the code is meant to do.
You’re so damn close unlocking SynergyFLEX 2.0 🙂 its not funny.
With the approach of having Re-parenting in check, it can be now a case of having programmatic instructions, to inject DOM pieces into the heart of your code. In that you load in pak1.swf, pak2.swf and so on into your code base as needed, then inject these little gems into the code packets. So if one were to assume that the ID’s are the nerve centre, and the control can be unknown, one would easily be able to adopt the above in a more abstract processes and reach the enlightment of FLEX 2 utopia 🙂
Pingback: Indefinite Articles » Flex - Separating Content from Code
I agree that on any decent sized project this is the way to go.
I really don’t like the approach of using MXML for everything as it means everything is public and it just feels sloppy.
Here’s an example of what i mean, and i think we should be avoiding (or a least not teaching people its the best way, eeek i know this is a pretty bold statement means Peter Ent obviously knows so much more than me). I pretty sure that any project that takes this approach, will come across problems as it grows. http://www.adobe.com/cfusion/webforums/forum/messageview.cfm?catid=585&threadid=1182156&enterthread=y
After saying that I’m still not totally happy with using a seperate AS file. It makes total sense to remove all AS from the MXML, and i’ve gone down this road on two large projects but i do find it a bit hindering and end up with so many bloody files open. Just gotta get used to close shit, when i’ve done with it i guess.
Guys, what about next approach for separating AS and mxml:
1. We have this code that is not good for us, because of code inside MXML.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Button label="Click Me!" click="trace('You clicked the button!');"/>
</mx:Application>
2. Let’s create AS class that extends Application, it will look like this:
package sample
{
import mx.core.Application;
public class SampleBase extends Application
{
}
}
and then let’s extend this class by mxml class:
3. Next we place button inside mxml:
<SampleBase xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*">
<mx:Button id="sampleButton" label="Click Me!"/>
</SampleBase>
and inside AS, also we will listen event from Button in AS:
package sample
{
import mx.core.Application;
import mx.controls.Button;
import mx.events.FlexEvent;
import flash.events.MouseEvent;
import flash.events.Event;
public class SampleBase extends Application
{
public var sampleButton : Button;
public function SampleBase() : void
{
addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
}
private function onCreationComplete(event : Event) : void
{
sampleButton.addEventListener(MouseEvent.CLICK, onButtonClick);
}
private function onButtonClick(event:MouseEvent) : void
{
trace(â€You clicked the button!â€);
}
}
}
So what do we have now:
1. Total separation AS from MXML.
2. In Cairngorm this approach can resolve one of the problems (currently View and ViewHelper are aware about each other == incapsulation is broken), in this approach we use inheritance and actually there is no ViewHelper needed.
Waiting for your comments.
Thanks Stas, I fixed your comment to properly display the MXML. I like your solution. It’s very clever.
Including Actionscript via the source property in a Script tag doesn’t quite feel right to me. By creating a subclass of Application (or whatever container that you’re extending), you’ll also get proper code completion in the MXML editor.
At first glance, I didn’t expect this code to work. I wondered if it would fail to compile if you declared the Button component in SampleBase and then declared it again in the MXML. Flex didn’t complain at all, and it works fine. If you plan to use this solution, remember to declare your subcomponents as public variables just like Flex does when it generates your code.
I’ve been experimenting with all sorts of flavors trying to get the right feel. Ugh.. nothing feels clean yet. My latest stuff is using the ActionScript subclassing technique described above to emulate a code behind (a la .Net/XAML). So far it’s pretty clean but can be very verbose. And sometimes my brain chokes because I treat it like a code behind when it really isn’t.
The other thing I’ve tried to do is to componentize my functionality through command classes.
I like it but it doesn’t work in all cases.
In some cases where I only need a single method or very little code it is so tempting to just toss it into the markup but… ugh.. inline script just feels wrong. I actually haven’t even gone down the path of includes yet. I don’t know… having a dangling AS file just feels a little weird to me. I guess I’m a purist, to a fault.
Anyway, it’s great to see this topic discussed. It’s something that I feel like I’ve really been struggling with to find something that’s comfortable, clean, simple, and elegant.
Oh, also an awkward thing about the subclassing technique is the naming of your files. You can’t have the .as and .mxml the same name. There is a conflict with the generated class. End up with stuff like…
NewDocumentDialog.mxml
NewDocumentDialogBehind.as
Kinda nasty
Right Paul, the names shouldn’t be the same!
For example we call AS file “xxxBase” and MXML file just “xxx”.
And I agree it’s verbose, but I have been developing with this technique quite for a long time and it’s more like a habit now 🙂
Aral Balkan has written a Flex Quick Start about “code behind” component development (using an AS class as your base for an MXML component). Like Paul’s “Behind” suffix and Stas’ “Base” suffix, Aral adds “Class” to the end of the component’s name. Personally, Base sounds the best to me so far, but I guess it’s up to your personal taste.
Hey guys, also check out the Pizza Service Flex 2 sample application in Arp. Arp uses code behind for Flash, Flex 1.5 and Flex 2 apps.
Make sure you checkout the latest from SVN (the release version is way too old and doesn’t contain the Flex stuff.)
http://svn1.cvsdude.com/osflash/arp/
Hope you enjoy the Quick Start 🙂
funny… I just refactored my classes to use Base. I like it better as well. It’s more explicit.
Really glad I found this post as I’m just about to embark on my first Flex project and I have been musing over how best to separate script from my .mxml files.
Stas, great example. That feels very intuitive to me.
I’ve not used an architectural framework before (not sure how beneficial it would be for me to use Cairngorm or Arp until I’ve actually got a little more Flex2 experience under my belt? I’d be really interested in your opinions on this, as I’m a little worried it could be counter productive for me at this stage, even though, given the size of my first task, using a framework would ideally be the way to go).
The first project my employer has tasked me with is going to be quite large, so I’ve been knowingly over-architecting all my test files to get a feel for building something bigger. Any tips I can glean from those with more experience will be a bonus 🙂
Steven Webster from Adobe Consulting has some good suggestions for when you should (or shouldn’t) start using Cairngorm. I personally have not used either architecture in any of my projects yet, and I suggest taking Steven’s advice to make sure that you know Flex well before starting with other frameworks to go on top of it.
Great, thanks Josh.
As for the extending thingies, we do it the other way around.
We create an mxml file and call it nameVisual, then we extend it with an actionscript class:
class name extends nameVisual
{
};
This way, inside the actionscript class, you have code hinting on what you defined in the mxml file.
Greetz Erik