This blog post is related to My LFPUG Presentation about Mate blog post (I know, it was 3 months ago, it’s a shame but I also must work for a living).
If you haven’t done it yet you should have a look first at our previous examples: #1, #2, #3, #4, #5, #6, #7, #8, #9 and #10.
In our previous example we’ve studied a simple implementation of the Presentation Pattern. In this configuration, the View has a reference to its presentation model (or at least to its interface). But what if you want it to be the other way around? The view exists for itself and the model is the one who has a reference to the view. This approach definitely is a prime candidate if you want to use views generated in Flash Catalyst then synchronised with Flash Builder with CatalystBuilderSync. You can easily modify your views without affecting the logic whatsoever. The view is dumb or passive as explained in this other article by Paul Williams. It’s also one of the patterns used in PureMVC, called Mediator and we will keep the name here. So, how is it possible with Mate?
Let’s have a look (source is available by right-clicking on the demo after launching it):
As you can see, the 2 views FirstPanel.mxml and SecondPanel.mxml are completely autonomous, without any reference to anything else nor any logic:
Demo #11: src/views/FirstPanel.mxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?xml version="1.0" encoding="utf-8"?> <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" width="298" height="164" layout="absolute" title="First Panel"> <mx:Button id="button1" label="Button One" left="30" verticalCenter="0"/> <mx:Button id="button2" label="Button Two" right="30" verticalCenter="0"/> </mx:Panel> |
Demo #11: src/views/SecondPanel.mxml
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" width="246" height="232" layout="absolute" title="Deuxieme Panel" borderStyle="inset" backgroundColor="#A5C5ED"> <mx:Button id="button1" label="Bouton Un" horizontalCenter="0" top="20" emphasized="true" cornerRadius="0"/> <mx:Button id="button2" label="Bouton Deux" horizontalCenter="0" bottom="20" cornerRadius="0" fillAlphas="[1.0, 1.0]" fillColors="[#FF0000, #FF0000]" color="#FFFFFF"/> </mx:Panel> |
Now the mediators which embed all the logic and the reference to their respective view (which is passed as an argument of the initMediator method):
Demo #11: src/views/mediators/FirstPanelMediator.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 | package views.mediators { import flash.events.EventDispatcher; import flash.events.MouseEvent; import mx.controls.Alert; import views.FirstPanel; public class FirstPanelMediator extends EventDispatcher { public var component : FirstPanel; public function initMediator(target : *) : void { component = target as FirstPanel; component.button1.addEventListener(MouseEvent.CLICK, button1_clickHandler); component.button2.addEventListener(MouseEvent.CLICK, button2_clickHandler); } protected function button1_clickHandler( event : MouseEvent ) : void { Alert.show("Button1 Clicked"); } protected function button2_clickHandler( event : MouseEvent ) : void { Alert.show("Button2 Clicked"); } } } |
Demo #11: src/views/mediators/SecondPanelMediator.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 | package views.mediators { import flash.events.EventDispatcher; import flash.events.MouseEvent; import mx.controls.Alert; import views.SecondPanel; public class SecondPanelMediator extends EventDispatcher { public var component : SecondPanel; public function initMediator(target : *) : void { component = target as SecondPanel; component.button1.addEventListener(MouseEvent.CLICK, button1_clickHandler); component.button2.addEventListener(MouseEvent.CLICK, button2_clickHandler); } protected function button1_clickHandler( event : MouseEvent ) : void { Alert.show("Oh, I do not like this."); } protected function button2_clickHandler( event : MouseEvent ) : void { Alert.show("Please, don't do that."); } } } |
And finally the eventMap which ties together views and mediators via injection:
Demo #11: src/maps/MainEventMap.mxml
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 | <?xml version="1.0" encoding="utf-8"?> <mate:EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:mate="http://mate.asfusion.com/"> <mx:Script> <![CDATA[ import views.SecondPanel; import views.mediators.SecondPanelMediator; import mx.events.FlexEvent; import views.FirstPanel; import views.mediators.FirstPanelMediator; ]]> </mx:Script> <mate:Debugger level="{Debugger.ALL}"/> <mate:Injectors target="{FirstPanel}"> <mate:MethodInvoker generator="{FirstPanelMediator}" method="initMediator" arguments="{event.injectorTarget}"/> </mate:Injectors> <mate:Injectors target="{SecondPanel}"> <mate:MethodInvoker generator="{SecondPanelMediator}" method="initMediator" arguments="{event.injectorTarget}"/> </mate:Injectors> </mate:EventMap> |
Whenever a view is instantiated then its related mediator is instantiated as well, its initMediator method is called and the injector’s target (the view: FirstPanel or SecondPanel) is passed as an argument. Important: note the use of Mate’s event.injectorTarget to retrieve the injector’s target reference. You cannot pass directly {FirstPanel} or {SecondPanel}. It wouldn’t work.
I’ll tell you what: this Mediator approach is quite simply my favourite at the moment as it leaves you with the maximum freedom to deal with the new Flex 4 paradigm (component + skin) without interfering with it at any point.
Next time (hopefully sooner than next month): Versioned Applications (think about Modules but more powerful)
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.

Subscribe




How would you call an event in SecondPanel from a button inside FirstPanel?
You should find an answer to this question in the previous examples, especially the Examples #8 and #9 about Modules which work pretty much the same way.
I just implemented this and had an issue where subsequent retrievals of the View and Mediator from cache by the EventMap would trigger the Injector to call that MethodInvoker multiple times. So, my Mediator was being initialized more than once and ended up with a component variable which wasn’t pointing at the right View.
Adding an “isInitialized” Boolean check to the initMediator() function should fix this, but I just wanted people to know that this is an issue they might run into as well.
The way the mediator directly accesses implementation details like button1 and button2 bothers me. What about injecting an IFirstPanel? Would that work?
Of course it is always possible to use interfaces but it usually only makes sense if your views are generic. In most situations each view’s structure and content are so specific you would end up with a combo of 3 files (mediator/interface/view) for every single view… Sounds to me like a massive overload when Flex, unlike some other languages like Objective-C, doesn’t specifically require it. But in the end it’s your choice anyway.
Learnt a whole lot from your Mate articles/examples! Thanks a million!!
Next time (hopefully sooner than next month): Versioned Applications (think about Modules but more powerful)
Any chance to read this last article ?
anyhow, thanks for all previous ones
Arf, you’re right, that one was dropped along the way. Unfortunately it doesn’t look too good about publishing this one quickly as I am pretty swamped at the moment… Sorry about that…
Started using Mate a few months back. But your Mate Tutorials still provide me with some excellent information that help me to get a better grip with the framework.
Thanks
Really good one, I did a simple app using this pattern and posted here