Last night, I was part of the RIARadio recording about RobotLegs. I have been supportive of the framework ever since I was introduced to it by Joel. We had an awesome time talking about Frameworks, OOP and RobotLegs. I raised a question to Shaun Smith and Joel Hooks about the presentation model vs Mediator and I pointed out that I haven’t seen a solution to the problem I presented on RobotLegs forums. See here. Joel challenged me to create my own implementation. I decided to accept the challenge and take a stab at it and see what I can come up with.
Problem
You cannot capture all the lifecycle events of a components ( such as PREINITIALIZE, INIT_PROGRESS, INITIALIZE & CREATION_COMPLETE) when using the mediator in Robotlegs. In addition I haven’t seen any implementation that uses the Presentation Model (PM) so you can do stuff before the component gets created or just drop an Presentation Model implementation you have done outside of the RobotLegs framework.
Under the hood
So why can’t we capture the component life cycle events in the Mediator?
The reason is that RobotLegs uses the contextView which is using the DisplayObjectContainer. The DisplayObjectContainer capture the event once the view is already added to the stage (see in 231 in MediatorMap.as)
The view gets added to the stage and than “onViewAdded” method being called and the mediator gets created. At this point it’s already too late, since most of the events to init the component have already been fired.
Meaning, even if you’ll change the mediatorBase code to the following:
public function preRegister():void
{
if (flexAvailable && (viewComponent is UIComponentClass) && !viewComponent['initialized'])
{
IEventDispatcher(viewComponent).addEventListener('preinitialize', onCreationComplete, false, 0, true);
}
else
{
onRegister();
}
}
You cannot guarantee it will fire the pre-initialize event, and in fact when I have done some testing I found out that many times the if statement doesn’t get executed and it uses the onRegister directly.
Solution
So the options were either to modify RobotLegs entirely or try to create a more elegant solution that will use RobotLegs architecture while providing the ability to create presentation model in RobotLegs. Since I couldn’t think of a solution other than creating my own mapping system for the presentation model I started modifying RobotLegs framework, however as I was modifying the framework it hit me that there is a more elegant solution using the existing architecture.
Feel free to view and download (right click to ‘view source’) the full example from here:

Implementation
Let’s take a look at the example in detail. My entry point, main MXML application, calls the context:ApplicationContext just like any Robotlegs (MVCS) implementation. I have added component that gets attached to the view called mainView
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:context="com.elad.application.*"
minWidth="1024" minHeight="768"
xmlns:view="com.elad.application.view.*">
<fx:Declarations>
<context:ApplicationContext contextView="{this}" />
</fx:Declarations>
<view:MainView id="mainView" width="100%" height="100%" />
</s:Application>
Using a presentation model will allows me to easy unit test my application better, since I can create test cases just for the logic and if needed test cases for the view. Additionally, I can replace my view easily and create different views for the same logic, which will help big time with Flex 4 new architecture and Flash Catalyst.
So using presentation model such as passive view I can than split my laundry to two piles, view and presenter:
View:
1. State is in the view
2. Transitions
3. View is passive and is not aware of the Presenter
Presenter:
1. Logic is in the Presenter.
2. Presenter observes view events
3. Presenter updates the view data.
4. Presenter ‘knows’ about the components in the view.
5. Presenter holds the data or point to a data class.
In fact, I have used the exact same example I created for Flash&Flex Magazine with very small modifications. Take a look at TweetListPresenter, which holds the responsibilities that I described:
package com.elad.application.view.presenter
{
import com.elad.application.view.TweetListView;
import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.events.FlexEvent;
import org.robotlegs.mvcs.Actor;
import utils.twitter.TwitterHelper;
import utils.twitter.events.TwitterHelperFailureEvent;
import utils.twitter.events.TwitterHelperSuccessEvent;
import utils.twitter.vo.TweetVO;
public class TweetListPresenter extends Actor
{
/**
* Corresponding view
*/
private var _tweetListView:TweetListView;
/**
* Method to go and retireve tweets every defined number of seconds
*
* @param seconds
*
*/
public function get tweetListView():TweetListView
{
return _tweetListView;
}
public function set tweetListView(value:TweetListView):void
{
_tweetListView = value;
}
/**
* Twitter helper utility class instance
*/
public var twitterHelper:TwitterHelper;
/**
* Holds a timer so we will be able to update list
*/
public var timer:Timer;
//--------------------------------------------------------------------------
//
// Default Constructor
//
//--------------------------------------------------------------------------
// called right after pre-init
public function TweetListPresenter()
{
_tweetListView = new TweetListView();
_tweetListView.width = 800;
_tweetListView.height = 400;
_tweetListView.addEventListener( FlexEvent.PREINITIALIZE, onPreinitialize );
_tweetListView.addEventListener( FlexEvent.INITIALIZE, onInitialize );
_tweetListView.addEventListener( FlexEvent.CREATION_COMPLETE, onComplete );
twitterHelper = new TwitterHelper();
twitterHelper.addEventListener( TwitterHelperSuccessEvent.RETRIEVE_TWEETS, onRetrieveTweets );
twitterHelper.addEventListener( TwitterHelperFailureEvent.SERVICE_FAILURE, onFaultRequest );
}
public function retrieveTweetsEveryFewSeconds( seconds:int ):void
{
timer = new Timer( seconds*1000, 100000 );
timer.addEventListener( TimerEvent.TIMER, onTimerHandler, false, 0, true );
timer.start();
}
//--------------------------------------------------------------------------
//
// Handlers
//
//--------------------------------------------------------------------------
private function onPreinitialize(event:FlexEvent):void
{
// implememt
trace("onPreinitialize");
}
private function onInitialize(event:FlexEvent):void
{
// implememt
trace("onInitialize");
}
private function onComplete(event:FlexEvent):void
{
trace("onComplete");
retrieveTweetsEveryFewSeconds( 2 );
}
/**
* Method to handle a timer event
*
* @param event
*
*/
private function onTimerHandler( event:TimerEvent ):void
{
twitterHelper.retrieveTweetsBasedOnHashTag( "FlashAndTheCity" );
}
/**
* Handler for results
*
* @param event
*
*/
private function onRetrieveTweets( event:TwitterHelperSuccessEvent ):void
{
var dataProvider:Array = new Array();
event.collection.forEach( function callback(item:TweetVO, index:int, vector:Vector.<TweetVO>):void {
dataProvider.push( item );
} );
this._tweetListView.dataGrid.dataProvider = dataProvider;
}
/**
* Handler for fault
*
* @param event
*
*/
private function onFaultRequest( event:TwitterHelperFailureEvent ):void
{
}
}
}
Couple of things to notice.
- Actor - The presenter extends Actor just like any other RobotLegs actor
- Component’s life cycle events - The default constructor creates the passive view and set the size as well as the component’s life cycle events
The view is passive and just holds the component (in our case a DataGrid):
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
width="400" height="300">
<mx:DataGrid id="dataGrid" width="500" height="400" />
</s:Group>
The next step is to create the mediator for the main view:
public class MainViewMediator extends Mediator
{
[Inject]
public var mainView:MainView;
[Inject]
public var tweetListPresenter:TweetListPresenter;
override public function onRegister():void
{
mainView.addElement( tweetListPresenter.tweetListView );
}
}
Notice that I am using the DI to inject the presenter just as we do to any Actor in RobotLegs:
[Inject] public var tweetListPresenter:TweetListPresenter;
And once the main view is registered I can than add the component to the display:
mainView.addElement( tweetListPresenter.tweetListView );
Lastly, I need to map everything up in the ApplicationContext class:
override public function startup():void
{
//todo: add commands
commandMap.mapEvent(ContextEvent.STARTUP, StartupCommand, ContextEvent, true);
// todo: Add Model
injector.mapSingleton( TweetListPresenter );
// todo: Add Services
// todo: Add View
mediatorMap.mapView(MainView, MainViewMediator);
// Startup complete
dispatchEvent( new ContextEvent( ContextEvent.STARTUP ) );
}
Take a look at the folder structure:

Feel free to download the full example from here, and let me know your thoughts.
Cheers