14
Aug
07

Flex Code-Behind Data Binding :: Part 1

I’m a little nutty when it comes to writing my view classes in Flex; I use MXML exclusively for layout and presentation, and code all the application and business logic in ActionScript…so you might be thinking, big deal, don’t you have to do that…well no…not really…in your MXML views you can set event handlers and data binging directly in the MXML, but I hate that, so I follow the code-behind technique pretty religiously, but with my own added twists here and there. And sure, it creates an extra abstraction layer, and the agile or ruby-type-simplistic-coders might say that’s overkill, but since most of my projects are quite large, I feel like the additional layer creates cleaner views that are ultimately easier to debug and unit test because of this decoupling.
That being said, I ran into a binding issue due to the chaining mechanism automatically done for you by binding in MXML. Let’s look at a very quick example — I’ll post a Part 2 that ties this into an actual application using Cairngorm soon.
Imagine that you have first and last name label components in a MXML view called EmployeeView.mxml and you want to bind those to a EmployeeModel in your ModelLocator; for the purpose of this example the view will also contain a button that makes a server call for the employee object, which is ultimately set to the EmployeeModel on a successful request — it might look something like this:
NOTE: This is all psuedo-code and has not been tested. Again, I’ll put up a more detailed version of this in a second post.
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
    xmlns:mx="http://www.adobe.com/2006/mxml"
    width="400" height="300">

    <mx:Script>
        <![CDATA[
        import com.brianmriley.sandbox.codebehind.model.MyModelLocator;

        private function getEmployeeButtonClickHandler(event:MouseEvent):void
	{
	    // assume we're using Cairngorm and dispatching a GetEmployeeEvent
	    // that's mapped to GetEmployeeCommand that uses GetEmployeeDelegate to
	    // request the employee XML with an HTTPService and then returns
	    // the successful response to GetEmployeeCommand, which does something
	    // like the following in it's public result(data:Object) method:
	    // MyModelLocator.getInstance().employeeModel = EmployeeModel(data);
	    //
	    // ...and theoretically the first and last name labels are then populated
	}
	]]>
    </mx:Script>

    <mx:VBox>
	<mx:Label
            id="firstNameLabel"
            text="{MyModelLocator.getInstance().employeeModel.firstName}" />
	<mx:Label
            id="lastNameLabel"
            text="{MyModelLocator.getInstance().employeeModel.lastName}" />
        <mx:Button
            id="getEmployeeButton"
            text="Get Employee" click="getEmployeeButtonClickHandler(event)" />
    </mx:VBox>

</mx:Canvas>
Now let’s change this to use code-behind. First I create a base AS component for EmployeeView.mxml and call it EmployeeComponent.as — I typically make a base, abstract-like AS class for some of this functionality too:
package
{
	import flash.events.MouseEvent;

	import mx.binding.utils.BindingUtils;
	import mx.containers.Canvas;
	import mx.controls.Button;
	import mx.controls.Label;
	import mx.events.FlexEvent;

	public class EmployeeComponent extends Canvas
	{
		public var firstNameLabel:Label
		public var lastNameLabel:Label
		public var getEmployeeButton:Button;

		public function EmployeeComponent()
		{
			super();

			this.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
		}

		protected function init():void
		{
			this.setMXMLViewEventHandlers();
			this.setMXMLViewBindings();
		}

		protected function setMXMLViewEventHandlers():void
		{
			this.getEmployeeButton.addEventListener(MouseEvent.CLICK, creationCompleteHandler);
		}

		protected function setMXMLViewBindings():void
		{
			BindingUtils.bindProperty(this.firstNameLabel, "text", MyModelLocator.getInstance().employeeModel, "firstName");
			BindingUtils.bindProperty(this.lastNameLabel, "text", MyModelLocator.getInstance().employeeModel, "lastName");
		}

		private function getEmployeeButtonClickHandler(event:MouseEvent):void
		{
			// assume we're using cairngorm and dispatching a GetEmployeeEvent
			// that's mapped to GetEmployeeCommand that uses GetEmployeeDelegate to
			// request the employee XML with an HTTPService and then returns
			// the succesful response to GetEmployeeCommand, which does something
			// like the following in it's public result(data:Object) method:
			// MyModelLocator.getInstance().employeeModel = EmployeeModel(data);
			//
			// ...and theoretically the first and last name labels are then populated
		}

		private function creationCompleteHandler(event:FlexEvent):void
		{
			this.init();
		}
	}
}
And change the EmployeeView.mxml to the following:
<?xml version="1.0" encoding="utf-8"?>
<local:EmployeeComponent
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:local="*"
	width="400" height="300">

	<mx:VBox>
		<mx:Label id="firstNameLabel" />
		<mx:Label id="lastNameLabel" />
		<mx:Button id="getEmployeeButton" text="Get Employee" />
	</mx:VBox>

</local:EmployeeComponent>
But if you run this, the data binding will not fire because we’re binding directly to the firstName and lastName properties in the EmployeeModel, and we’re updating the entire EmployeeModel (in the command). This does not happen when you bind directly in the MXML because it notation forces the binding to chain up the object, so it will detect the change on the entire employeeModel in the ModelLocator and fire the binding for it’s properties. To get around this in the code-behind technique, one must change the following line from:
BindingUtils.bindProperty(this.firstNameLabel, "text", MyModelLocator.getInstance().employeeModel, "firstName");
BindingUtils.bindProperty(this.firstNameLabel, "text", MyModelLocator.getInstance(), ["employeeModel", "firstName"]);
This does enforce the binding to chain (like in the MXML version) by saying, first look at the employeeModel, and if it changes, then fire the binding for it’s property firstName.
Another approach to this is the following:
var employeeModelChangeWatcher:ChangeWatcher = ChangeWatcher.watch(MyModelLocator.getInstance(), "employeeModel", employeeModelChangeWatcherHandler);

private function employeeModelChangeWatcherHandler(event:Event):void
{
	this.firstNameLabel.text = MyModelLocator.getInstance().employeeModel.firstName;
}
And while it is indeed more code, it may allow you to do more than just bind the property — you might want to run some other related functions when the properties of the employeeModel changes…
Advertisements

2 Responses to “Flex Code-Behind Data Binding :: Part 1”


  1. August 13, 2009 at 3:22 pm

    Bahrian,

    We dee fuck is part two?
    Eet’s only beeeeean two fucking years Bahrian!!!

  2. August 13, 2009 at 3:23 pm

    and I steel have this oppportunity for you. $50 dollar an hour Bahrian!!!!!
    Please, please, call your friend Ba.


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: