Aug 17

In the past year I have been using the Robotlegs MVCS framework for AS3 extensively; one of the bigger challenges that I encountered was creating an application with several self contained modules that needed to communicate with each other. Joel Hooks & Stray, a couple of the main contributors to the Robotlegs framework created a modular utility which resolves this particular issue within the Robotlegs framework. Joel Hooks also has a very informative post and a tutorial / demo posted on his blog.

I created a very simple demo which I used to learn how to implement the Robotlegs Modular Utility and this post will provide a step by step walkthrough of how to setup a modular Robotlegs project in Flex 3.5. This tutorial is for people that have some knowledge of the Robotlegs framework & Flex. You can learn more about Robotlegs at the Robotlegs knowledgebase.

To get started you will need the following:

The simple demo application features two modules and an application shell. The first module is a button which will send the timestamp from the Date Object’s getTime() method to the second module, which will then display the timestamp. The application shell simple holds the two modules.

Here is the demo & source code for those of you that don’t want to read the whole tutorial. The links are provided again at the end of the posting for those that want to finish reading the tutorial.

The first step is to create a new project in Flex and then to copy the files for the Robotlegs Modular Utilities into the src folder of your project and then to create the project structure for the sample application. The project tree in Flex should look like the following image after you have completed setting up the project.

Flex Project Structure

Part 1 – setting up the first module – ButtonModule

Now that the project has been setup, we’ll begin with creating the view for the ButtonModule; simply create a new MXML Component named ButtonModule.mxml under the buttonModule folder.

Code for ButtonModule.mxml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="200" height="200">
	<mx:Script>
		<![CDATA[
			import org.robotlegs.utilities.modular.core.IModuleContext;
			import org.robotlegs.core.IInjector;
 
			protected var context:IModuleContext;
 
			[Inject]
			public function set parentInjector(value:IInjector):void
			{
				context = new ButtonModuleContext(this, value);
			}
		]]>
	</mx:Script>
	<mx:Button id="myButton" width="100%" />
</mx:Canvas>

The ButtonModule.mxml view defines the UI of the ButtonModule and also initializes the ButtonModuleContext by specifying the contextView and the injector when
the ButtonModule view is instantiated. The contextView is specifies the view that scopes the ModuleContext; i.e. the ModuleContext is only able to map injections/mediators within the contextView. The injector is used to insert classes into any other classes that as long as both the target and source classes are mapped within the scope of the ModuleContext.

Next, we need to create the a context for the ButtonModule; create an ActionScript Class named ButtonModuleContext.as with a superclass of ModuleContext under the buttonModule folder.

Code for ButtonModuleContext.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.digitaldogbyte.buttonModule
{
	import com.digitaldogbyte.buttonModule.views.ButtonModuleMediator;
 
	import flash.display.DisplayObjectContainer;
	import flash.system.ApplicationDomain;
 
	import org.robotlegs.core.IInjector;
	import org.robotlegs.utilities.modular.mvcs.ModuleContext;
 
	public class ButtonModuleContext extends ModuleContext
	{
		public function ButtonModuleContext(contextView:DisplayObjectContainer, injector:IInjector)
		{
			super(contextView, true, injector);
		}
 
		override public function startup():void
		{
			trace("button module context");
			mediatorMap.mapView(ButtonModule, ButtonModuleMediator);
		}
 
	}
}

The ButtonModuleContext simply maps the ButtonModule view to the ButtonModuleMediator. The mediator acts as the “code-behind” for the view; it is often used to map event listeners to event handlers for the view and is often contains business logic & presentation logic for view.

The mediator is the last piece required to complete the ButtonModule; create an ActionScript Class named ButtonModuleMediator.as with a superclass of ModuleMediator under the buttonModule/views folder.

Code for ButtonModuleMediator.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.digitaldogbyte.buttonModule.views
{
	import com.digitaldogbyte.buttonModule.ButtonModule;
	import com.digitaldogbyte.labelModule.events.LabelModuleEvent;
 
	import flash.events.MouseEvent;
 
	import org.robotlegs.utilities.modular.mvcs.ModuleMediator;
 
	public class ButtonModuleMediator extends ModuleMediator
	{
		[Inject]
		public var view:ButtonModule;
 
		public function ButtonModuleMediator()
		{
			super();
		}
 
		override public function onRegister():void
		{
			view.myButton.label = "display timestamp";
			addViewListener(MouseEvent.CLICK, onButtonClicked, MouseEvent);
		}
 
		private function onButtonClicked(event:MouseEvent):void
		{
			var date:Date = new Date();
 
			dispatchToModules(new LabelModuleEvent(LabelModuleEvent.DISPLAY_MESSAGE, date.getTime()));
		}
 
	}
}

In the ButtonModuleMediator, we are telling the mediator to listen for a mouse click on the view and handle the mouse click by invoking the onButtonClicked method. The onButtonClicked method then invokes the dispatchToModules method (inherited from ModuleMediator) which checks to see which module has a listener for the LabelModuleEvent.DISPLAY_MESSAGE event and then dispatches the event to that module.

At this point, your project explorer should look like this:

Flex Project Structure with ButtonModule

Part 2 – setting up the second module – LabelModule

The steps for creating the LabelModule are nearly identical to the steps taken to create the ButtonModule. You will need to create a view, context and mediator.

Code for LabelModule view – LabelModule.mxml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="200" height="200">
	<mx:Script>
		<![CDATA[
			import org.robotlegs.utilities.modular.core.IModuleContext;
			import org.robotlegs.core.IInjector;
 
			protected var context:IModuleContext;
 
			[Inject]
			public function set parentInjector(value:IInjector):void
			{
				context = new LabelModuleContext(this, value);
			}
		]]>
	</mx:Script>
	<mx:Label id="myLabel" />
</mx:Canvas>

Code for LabelModule context – LabelModuleContext.as with a superclass of ModuleContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.digitaldogbyte.labelModule
{
	import com.digitaldogbyte.labelModule.view.LabelModuleMediator;
 
	import flash.display.DisplayObjectContainer;
	import flash.system.ApplicationDomain;
 
	import org.robotlegs.core.IInjector;
	import org.robotlegs.utilities.modular.mvcs.ModuleContext;
 
	public class LabelModuleContext extends ModuleContext
	{
		public function LabelModuleContext(contextView:DisplayObjectContainer, injector:IInjector)
		{
			super(contextView, true, injector);
		}
 
		override public function startup():void
		{
			trace("label module context");
			mediatorMap.mapView(LabelModule, LabelModuleMediator);
		}
 
	}
}

Code for LabelModule mediator – LabelModuleMediator.as with a superclass of ModuleMediator in the labelModule/views folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.digitaldogbyte.labelModule.view
{
	import com.digitaldogbyte.labelModule.LabelModule;
	import com.digitaldogbyte.labelModule.events.LabelModuleEvent;
 
	import org.robotlegs.utilities.modular.mvcs.ModuleMediator;
 
	public class LabelModuleMediator extends ModuleMediator
	{
		[Inject]
		public var view:LabelModule;
 
		public function LabelModuleMediator()
		{
			super();
		}
 
		override public function onRegister():void
		{
			setMessage("timestamp will display here");
			eventMap.mapListener(moduleDispatcher, LabelModuleEvent.DISPLAY_MESSAGE, onDisplayMessage);
		}
 
		private function onDisplayMessage(event:LabelModuleEvent):void
		{
			if (event != null)
			{
				if (event.data != null)
				{
					setMessage(event.data.toString());
				}
				else
				{
					setMessage("event data was null");
				}
			}
			else
			{
				setMessage("event was null");
			}
		}
 
		private function setMessage(message:String):void
		{
			view.myLabel.text = message;	
		}
 
	}
}

In the LabelModuleMediator you will notice that we are register the onDisplayMessage event handler for the LabelModuleEvent.DISPLAY_MESSAGE event.

To allow communication between the ButtonModule and LabelModule, we need to create a custom event. I decided to create the event as the LabelModuleEvent since the LabelModule is the module that will be listening and handling the event, while the ButtonModule only needs to dispatch the event.

The event can be created by adding a new ActionScript class named LabelModuleEvent.as with a superclass of Event in the labelModule/events folder.

Code for LabelModuleEvent.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.digitaldogbyte.labelModule.events
{
	import flash.events.Event;
 
	public class LabelModuleEvent extends Event
	{
		public static const DISPLAY_MESSAGE:String = "displayMessage";
 
		private var _data:Object;
 
		public function LabelModuleEvent(type:String, data:Object, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			_data = data;
			super(type, bubbles, cancelable);
		}
 
		override public function clone():Event
		{
			return new LabelModuleEvent(type, bubbles, cancelable);
		}
 
		public function get data():Object
		{
			return _data;
		}		
 
	}
}

At this point, your project explorer should look like this:

Flex Project Structure with LabelModule

Part 3 – setting up the application shell – ApplicationShell

You will need to create a view, context and mediator for the ApplicationShell.

Code for ApplicationShell view – ApplicationShell.mxml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" preinitialize="preinit();" width="100%" height="100%" xmlns:buttonModule="com.digitaldogbyte.buttonModule.*" xmlns:labelModule="com.digitaldogbyte.labelModule.*">
	<mx:Script>
		<![CDATA[
			import org.robotlegs.utilities.modular.mvcs.ModuleContext;
 
			protected var _context:ApplicationShellContext;
 
			protected function preinit():void
			{
				_context = new ApplicationShellContext(this);
			}
		]]>
	</mx:Script>
	<mx:HBox>
		<buttonModule:ButtonModule id="buttonModule" />
		<labelModule:LabelModule id="labelModule" />
	</mx:HBox>
</mx:Canvas>

Code for the ApplicationShell context – ApplicationShellContext.as with superclass of ModuleContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.digitaldogbyte.applicationShell
{
	import com.digitaldogbyte.applicationShell.views.ApplicationShellMediator;
	import com.digitaldogbyte.buttonModule.ButtonModule;
	import com.digitaldogbyte.labelModule.LabelModule;
 
	import flash.display.DisplayObjectContainer;
	import flash.system.ApplicationDomain;
 
	import org.robotlegs.core.IInjector;
	import org.robotlegs.utilities.modular.mvcs.ModuleContext;
 
	public class ApplicationShellConteThext extends ModuleContext
	{
		public function ApplicationShellContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true, parentInjector:IInjector=null, applicationDomain:ApplicationDomain=null)
		{
			super(contextView, autoStartup, parentInjector, applicationDomain);
		}
 
		override public function startup():void
		{
			trace("application shell context");
 
			viewMap.mapType(ButtonModule);
			viewMap.mapType(LabelModule);
 
			mediatorMap.mapView(ApplicationShell, ApplicationShellMediator);
		}
 
	}
}

Code for the ApplicationShell mediator – ApplicationShellMediator.as with superclass of ModuleMediator within the applicationShell/views folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.digitaldogbyte.applicationShell.views
{
	import com.digitaldogbyte.applicationShell.ApplicationShell;
 
	import org.robotlegs.utilities.modular.mvcs.ModuleMediator;
 
	public class ApplicationShellMediator extends ModuleMediator
	{
		[Inject]
		public var view:ApplicationShell;
 
		public function ApplicationShellMediator()
		{
			super();
		}		
	}
}

The final project structure should look like this:

Flex Project Structure with ApplicationShell

Demo & source files for the tutorial.

3 Responses to “Robotlegs Modular Utilities Tutorial”

  1. Glenn Goodrich Says:

    This was very helpful, thanks!

  2. Simple Modular Robotlegs at Jozef Chúťka's blog Says:

    [...] are some interesting sources for building robotlegs with modules (Modular Robotlegs, DynModules, Modular Tutorial ) but it took me some time to grab only the key functionality. So, I have decided to create the [...]

  3. alan Says:

    Thanks:) How to dynamic manager modular. if I don’t wana loader buttonModule
    and labelModule in the same time?

Leave a Reply