Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: Every view component can be linked to a Mediator?  (Read 8607 times)
seb
Newbie
*
Posts: 8


View Profile Email
« on: April 22, 2009, 05:48:51 »

Hi,

I have a problem with associating a Mediator to a specific component inside a view component (mxml).
I explain : in a Tabs.mxml component I have a TabNavigator containing 4 Panel, each one having a specific id. For one of these Panels components, let's say panel with id="testPanel", I want to link a specific Mediator : "TestTabMediator". I have registered TestTabMediator to the facade with the specific "testPanel". From "testPanel" I dispatch an Event and TestTabMediator is listenning for it and then calls his "test" method.
But when I dispatch the Event from Panel "testPanel", I never pass inside "test" method from TestTabMediator.
After many tests and questions, I tried to use the TabsMediator (linked to Tabs.mxml) instead of the TestTabMediator (linked to the Panel "testPanel") to listen for the Event. And this solution works.

So here is my question : has a Mediator to be linked only to custom mxml components and can not be linked to <mx:...> components?

I'm sorry I do not have the code near me, but I can post it later if needed.

Thank you for your answer.

Seb
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: April 22, 2009, 07:42:04 »

Sounds as if you may be grappling the standard 'deferred instantiation' issue. Check the FAQ entry for 'deferred instantiation', or read the article in the News section about the Slacker demo. Let me know if this doesn't address your problem.

-=Cliff> 
Logged
Ondina
Sr. Member
****
Posts: 86


View Profile Email
« Reply #2 on: April 22, 2009, 10:52:26 »

It seems, that the issue of deferred instantiation in Flex and the way puremvc registers the mediators, is something that almost every beginner has to deal with.

The Slacker Demo is indeed the answer to this dilemma.

But there is a slight difference between the Slacker Demo and how many developers build their navigation.
In the Slacker Demo you have to have a SplashView in order to get it work.
The SplashView doesn't have a Mediator.

But not always is it possible to have such a View without a Mediator.

For my project I needed a TabBar + ViewStack to navigate through the views.
In fact I have nested ViewStacks.
I have a MainView that contains the ViewStack and a MainViewMediator.
I register the mediator for the first view of the stack in the onRegister()method of the MainViewMediator. It works.

I thought, maybe it could help someone to see how I did it.
It is something I did when I started with puremvc, so there are imperfections there!
Especially there is an unorthodox way of getting the views' names when I register their mediators, but I had a good reason for doing so. Cliff will chide me for this!! And you should do it like in the SlackerDemo not like I did it.

I wanted to attach the example, but attachments are no longer allowed. So I'll post parts of it in here.

I hope it will help someone.

MainView
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:views="com.view.component.*" >
<mx:Script>
<![CDATA[
public static const TWO_CREATED:String       = 'twoViewCreated';
public static const THREE_CREATED:String    = 'threeViewCreated';

public var activeView:Object;

private function sendEvent(event:Event, action:String ):void{
activeView = event.currentTarget;
dispatchEvent(new Event( action, true ));
}
private function setActiveView(event:Event):void{
activeView = event.currentTarget.getChildAt(0);
}
]]>
</mx:Script>
<mx:TabBar id="mainTabBar" dataProvider="{mainViewStack}" />
<mx:ViewStack id="mainViewStack" childAdd="setActiveView(event)">
<views:OneView label="One" id="OneView"/>
<views:TwoView label="Two" id="TwoView" creationComplete="sendEvent(event, TWO_CREATED)"/>
<views:ThreeView label="Three" id="ThreeView" creationComplete="sendEvent(event, THREE_CREATED);"/>
</mx:ViewStack>
</mx:Canvas>


MainViewMediator
package com.view.mediator
{
   import com.view.component.MainView;
   
   import flash.events.Event;
   
   import org.puremvc.as3.multicore.interfaces.IMediator;
   import org.puremvc.as3.multicore.patterns.mediator.Mediator;

   public class MainViewMediator extends Mediator implements IMediator
   {
      public static const NAME:String = 'MainViewMediator';
      
      public function MainViewMediator(viewComponent: MainView)
      {
         super(NAME, viewComponent);
      }
      protected function get mainView(): MainView
      {
         return viewComponent as MainView;
      }
      override public function onRegister( ):void
      {
         mainView.addEventListener( MainView.TWO_CREATED, onViewsCreated );
         mainView.addEventListener( MainView.THREE_CREATED, onViewsCreated );
         //HERE IS THE TRICK: register the mediator for the first view in the stack
         checkForMediator( mainView.activeView );
      }
      protected function onViewsCreated( event:Event ):void
      {
         checkForMediator( mainView.activeView );
         //checkForMediator( event.currentTarget.activeView );
      }
      protected function checkForMediator(  child:Object ):void
      {
         switch ( child.id )
         {
            case "OneView":
               if ( ! facade.hasMediator( OneViewMediator.NAME ) )
               facade.registerMediator(new OneViewMediator( child ));
            break;
            case "TwoView":
               if ( ! facade.hasMediator( TwoViewMediator.NAME ) )
               facade.registerMediator(new TwoViewMediator( child ));
            break;
            case "ThreeView":
               if ( ! facade.hasMediator( ThreeViewMediator.NAME ) )
               facade.registerMediator(new ThreeViewMediator( child ));
            break;
         }
      }       
   }
}

The second View has also a TabBar and a ViewStack, but the post would be too long if I posted the entire code.

Ondina
« Last Edit: April 23, 2009, 03:12:53 by Ondina » Logged

~ Ondina ~
Ondina
Sr. Member
****
Posts: 86


View Profile Email
« Reply #3 on: April 25, 2009, 03:51:32 »

And here is how I actually use it in my current project:

TwoView.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:views="com.view.component.*"
creationComplete="addMyListeners()">
   <mx:Script>
   <![CDATA[
      import mx.events.FlexEvent;
      
      public static const SECOND_STACK:String   = 'SecondStack';
      
      public var activeView:Object =  new Object();
      public var numberOfViews:uint = 0;
      public var visitedViews:uint = 0;
      
      private function sendEvent( event:Event ):void{
         dispatchEvent( new Event( SECOND_STACK , true ) );
      }
      private function setFirstView( event:Event ):void{
         activeView = secondViewStack.selectedChild;
      }
      private function addMyListeners():void{
         numberOfViews = secondViewStack.numChildren;
         for (var i:uint=0; i<numberOfViews; i++){
            secondViewStack.getChildAt(i).addEventListener( FlexEvent.CREATION_COMPLETE, sendEvent );
         }
      }
      public function removeMyListeners():void{
         for (var i:uint=0; i<numberOfViews; i++){
            secondViewStack.getChildAt(i).removeEventListener( FlexEvent.CREATION_COMPLETE, sendEvent );
         }
      }
   ]]>
   </mx:Script>
   <mx:Binding source="secondViewStack.selectedChild" destination="activeView"/>
   <mx:TabBar id="secondTabBar" dataProvider="{secondViewStack}" styleName="secondTabBar" top="5" left="80"/>
   <mx:ViewStack id="secondViewStack" childAdd="setFirstView(event)" top="30" left="80" width="70%" height="90%" >
      <views:SubOneView label="SubOne" id="SubOneView"/>
      <views:SubTwoView label="SubTwo" id="SubTwoView"/>
      <views:SubThreeView label="SubThree" id="SubThreeView"/>   
   </mx:ViewStack>
</mx:Canvas>

TwoViewMediator.as
package com.view.mediator
{
   import com.view.component.TwoView;
   
   import flash.events.Event;
   
   import org.puremvc.as3.multicore.interfaces.IMediator;
   import org.puremvc.as3.multicore.patterns.mediator.Mediator;
   
   public class TwoViewMediator extends Mediator implements IMediator
   {
      public static const NAME:String = 'TwoViewMediator';
      
      public function TwoViewMediator( viewComponent: Object )
      {
         super( NAME, viewComponent );
      }
      protected function get twoView(): TwoView
      {
         return viewComponent as TwoView;
      }
      override public function onRegister():void
      {
         twoView.addEventListener( TwoView.SECOND_STACK, onViewCreated );
         checkForMediator( twoView.activeView );
      }
      protected function onViewCreated( event:Event ):void
      {
         checkForMediator( twoView.activeView );
      }
      protected function checkForMediator( child:Object ):void
      {
         twoView.visitedViews++;
         switch ( child.id )
         {
            case "SubOneView":
               if ( ! facade.hasMediator( SubOneViewMediator.NAME ) )
               facade.registerMediator(new SubOneViewMediator( child ));
            break;
            case "SubTwoView":
               if ( ! facade.hasMediator( SubTwoViewMediator.NAME ) )
               facade.registerMediator(new SubTwoViewMediator( child ));
            break;
            case "SubThreeView":
               if ( ! facade.hasMediator( SubThreeViewMediator.NAME ) )
               facade.registerMediator(new SubThreeViewMediator( child ));
            break;    
         }
         if(twoView.visitedViews==twoView.numberOfViews){
            twoView.removeEventListener( TwoView.SECOND_STACK, onViewCreated );
            twoView.removeMyListeners();
         }
      }       
   }
}

I would like to hear a suggestion for a better approach or other ways of doing this.
Is it bad not to use constants for every View, that dispatches an event on creationComplete? Maybe I can't see the bad consequences of it.
The way I handle this allows me to change the Views' order without having to change the constants or anything else. And also I have fewer constants in the View and Mediator.

Ondina
Logged

~ Ondina ~
Pages: [1]
Print