Go Tripod

Building a medium to large scale Flex App using Cairngorm (Part 3)

Tue Jun 10 2008

In Parts 1 & 2 we setup Cairngorm and our models. In Part 3 we will look at how we will make use of the controller, using commands to handle events, chaining together a series of commands using Cairngorm’s SequenceCommand and creating custom CairngormEvents.

Controller

In part 1 we created a class that extends Cairngorm’s FrontController. This controller allows us to register event handlers on Cairngorm’s custom event dispatcher. But rather than creating each event handler directly in Cairngorm’s front controller (as we would in EasyMVC) we use the command pattern to organise our event handlers into separate classes.

As our app grows, this separation into commands helps keep our application easily maintainable.

Commands

Cairngorm provides an interface named ICommand, that command classes must implement. This interface enforces an execute() function which passes in a a CairngormEvent.

As an example, we are now going to create a command for changing the application’s state between it’s default logged out state, logged in state and admin state. If you remember back to Part 2, we created a Session model and stored Main.mxml’s view state here using binding. We will now create a command that will change this state.

Firstly we start with the actual command class that will handle this event by creating a new ActionScript class that implements ICommand in the controller/commands folder. This command will fire when we dispatch the appropriate CairngormEvent. By default the CairngormEvent class has a data property that allows us to pass information to the command, in this case we want to pass the state that we want the command to change our Main.mxml viewstate to.

package uk.co.clockobj.cairngormdemo.controller.commands
{
	import com.adobe.cairngorm.commands.ICommand;
	import com.adobe.cairngorm.control.CairngormEvent;

	import uk.co.clockobj.cairngormdemo.model.ModelLocator;

	public class ChangeApplicationStateCommand implements ICommand
	{
		public function ChangeApplicationStateCommand()
		{
		}

		public function execute(event:CairngormEvent):void
		{
			ModelLocator.getInstance().session.appState = String( event.data );
		}

	}
}

Once we have written our command, we need to register the class with our controller. The FrontController that we extended provides an addCommand method that registers our command as an event listener for a specific named event.

Like native flex events, Cairngorm uses a name property on the event (of type string) to track which command will handle which event. By convention we store our event names as static string constants in the Controller.

package uk.co.clockobj.cairngormdemo.controller
{
	import com.adobe.cairngorm.control.FrontController;

	import uk.co.clockobj.cairngormdemo.controller.commands.ChangeApplicationStateCommand;

	public class AppController extends FrontController
	{
		public function AppController()
		{
			super();
			initialiseCommands();
		}

		private function initialiseCommands() : void
		{
			addCommand(CHANGE_APP_STATE, ChangeApplicationStateCommand)
		}

		public static const CHANGE_APP_STATE : String = "changeAppState";
	}
}

With our command registered we can now call it globally within our application using the following code. Note: If you remember back to part 2 we stored the three view states for Main.mxml as static constants on our Session model.

var ce : CairngormEvent = new CairngormEvent()
ce.data = SessionModel.APP_STATE_LOGGED_IN;
CairngormEventDispatcher.getInstance().dispatchEvent( ce );

If we were not passing any data, we could obviously do this in one line. Cairngorm’s data property is useful for passing all kinds of data, however in some cases you may need to pass more that one bit of data. For example a username and password, to a login command.

There are many ways we could do this, one of the easiest is to create a dynamic object instance to send the data over in. i.e.

var ce : CairngormEvent = new CairngormEvent(AppController.LOGIN_COMMAND)
ce.data = { username : "jon" , password: "baker" };
CairngormEventDispatcher.getInstance().dispatchEvent( ce );

Then in our command we can extract these values:

public function execute( event : CairngormEvent ):void
{
	var username : String = event.data.username;
	var password : String = event.data.password;

Custom events

The above method is fine for ad hoc requirements but if you need to formalise this, we need to create a custom CairngormEvent.

We do this by extending the CairngormEvent and including (in this case) a username and password property to our extended class.

package uk.co.clockobj.cairngormdemo.controller.events
{
	import com.adobe.cairngorm.control.CairngormEvent;

	public class LoginEvent extends CairngormEvent
	{

		public var username : String;
		public var password : String;

		public function LoginEvent(type:String, username : String = "", password : String = "", bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
			this.username = username;
			this.password = password;
		}

	}
}

Note: I have added code to allow the username and password to the constructor, this is useful for dispatching the event from one line of code.

Chaining Commands Together

There are times when developing an application that we will want to run a command from within another command. For this we need to use Cairngorm’s built in SequenceCommand class.

So for example on logging into our application, we will want to change the application state to either the logged in state or the admin state, based on the user’s role. We could do this directly from our login command but we have an event for this so we want to reuse that command.

For any command that wants to make a call to an additional command, the calling class must extend SequenceCommand;

Note: With the example above we are making use of a service call to log a user in. I will first cover Services and the Service Locator classes in the next part, so to avoid confusion, I will cover these in Part 4 and finish up by returning to the example sequence command discussed above.

In Part 4, I will discuss how we use our ServiceLocator class we created in Part 1 to locate our services and how we will call and respond to these service calls from our commands.

Contents:

Part 1 – Setting up a project for Cairngorm
Part 2 – The Model
Part 3 – Commands
Part 4 – Services
Cairngorm Demo Source Files

Got an idea for a project?

Need a website? Web-enabled software to streamline your business? Just some advice?