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):

Mate example

#11 Mediator (a la PureMVC) (click to Launch)


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.

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...