A module's mediator not calling onRegister when added to stage

Tony Smith's Avatar

Tony Smith

10 May, 2011 04:15 PM

I am not sure if this is by design but it doesn't seem like my ModuleMediator is not calling onRegister() when it is added to the stage. It seems to only call onRegister() when it first loads.

I am using Flex 4 States and I am loading the module into a container that is controlled by one of the states via includeIn='theState' which adds/removes the component from the stage/displaylist based on currentState.

Normally, any mediated component that is controlled by States will call onRegister when that state is set. But this does not happen on modules that are mediated. On the bright side (sort of), all the modules children that are mediated do call onRegister().

  1. Support Staff 1 Posted by Stray on 10 May, 2011 05:05 PM

    Stray's Avatar

    In flex the mediator waits for creationComplete from the view before running onRegister.

    Might that be relevant?

    Stray

  2. 2 Posted by Tony Smith on 10 May, 2011 05:40 PM

    Tony Smith's Avatar

    Ah, gotcha, very interesting. So that would mean that the state change on the container holding the module is somehow causing its children to have to be recreated. But I know that State change only acts on the displaylist. So a change in state that adds an item that has already been created, just dispatches an addedToStage event.

    I created a test with nested stateful containers and I was unable to get any of them to dispatch creationComplete after it had been fired once.

    I can't dig any more right now but I might be able to throw a proper isolated test together later.

    Thanks!

  3. 3 Posted by Tony Smith on 10 May, 2011 05:53 PM

    Tony Smith's Avatar

    OK, this just got stranger. I put a breakpoint on someView's creationComplete and a breakpoint on someViewMediator's onRegister. When I change up the module's holder's state (so that is it is removed from stage) and then change the state back (re-add to stage) the view's creationComplete is NOT dispatched but the onRegister method IS called.

    Are you sure onRegister isn't called when something is added to the stage? I just don't get it :-(

  4. 4 Posted by Weyert on 10 May, 2011 10:18 PM

    Weyert's Avatar

    As far as I know creationComplete gets dispatched when the Flex component has created all his children and called updateDisplayList-method once. I am quite confident it wont get called each time you add and remove the component from the stage because the component is already initialised. I think createChildren is only called once the first time.

  5. 5 Posted by Tony Smith on 10 May, 2011 10:26 PM

    Tony Smith's Avatar

    Oh I know but that is what makes it so odd. At the very core, I was able to see a mediator fire onRegister without it's view firing creationComplete. The CreationComplete event is firing as I would expect but if onRegister() is only called when its view dispatches creationComplete, then what was really calling it? cue Twilight Zone music. Unfortunately, I do not have the RL source code installed in my workspace so I can't trace back through to find out.

  6. Support Staff 6 Posted by creynders on 11 May, 2011 07:18 AM

    creynders's Avatar

    AFAIK onRegister IS called when a display object is added to the stage, not on creationComplete, since that's a flex-specific event.

  7. 7 Posted by Weyert on 11 May, 2011 07:48 AM

    Weyert's Avatar

    Yes, but he is referring to Flex 4 states meaning is using UIComponents. By my knowledge Flex States will add or remove components from the stage. I think he wants to have onRegister triggered each time the child component gets added/removed from stage while changing the view state of the parent component.

    In that case I would expect ADDED_TO_STAGE should just work fine but the MediatorMap class is detecting if Flex is being used and then only listens to creationComplete-events. I am not sure how you can mix them.

  8. Support Staff 8 Posted by Stray on 11 May, 2011 08:02 AM

    Stray's Avatar

    Hi Tony,

    The flow is like this:

    1. MediatorMap listens for ADDED_TO_STAGE
    2. On ADDED_TO_STAGE the MediatorMap creates and populates the mediator
    3. The MediatorMap then calls preRegister in the Mediator (inside MediatorBase)
    4. preRegister then does this:

      public function preRegister():void {

       removed = false;
      
       if (flexAvailable 
           && (viewComponent is UIComponentClass) 
           && !viewComponent['initialized'])
       {
           IEventDispatcher(viewComponent).addEventListener
               ('creationComplete', 
               onCreationComplete, false, 0, true);
       }
       else
       {
           onRegister();
       }
      

      }

    Reference: Line 66 of https://github.com/robotlegs/robotlegs-framework/blob/master/src/or...

    We have to use the strings obviously rather than static constants so that we can avoid pulling the flex-specific classes in. (Though actually we should still make these constants in our own class, will do that in our next update probably).

    So - if your Flex UIComponent is not yet initialized, it waits for creationComplete.
    If your Flex UIComponent is already initialized then onRegister runs immediately. If your view isn't a Flex UIComponent then onRegister always immediately.

    This logic is all in MediatorBase, not Mediator, so you're free to override it in your Mediator.

    In fact - that would be the best way to deal with the fact that you don't have the source. If you added the existing preRegister function as an override in your specific mediator then you could add traces etc to work out what's going on.

    It's almost as if we planned for this possibility... I'm not sure we did but boy it's a good debugging power-up!

    Stray

  9. 9 Posted by Tony Smith on 11 May, 2011 02:14 PM

    Tony Smith's Avatar

    Yes, sorry, I am working with Flex 4.

    Well, if onRegister is called when ever a component is added to the stage, then I am back to the original strangeness.

    Say the application loads and loads the module. Also say that I have already toggled once or twice between the two states. Now when I continue to toggle between states, every time I toggle to state 'ShowModule_B', Module_B's moduleMediator is not calling onRegister but all mediators that are children of the module are calling onRegister.

    If I am not being clear, feel free to say so for I am lord of the worst-questionaskers.

     <s:states>
          <s:State name="ShowModule_A" />
          <s:State name="ShowModule_B" />
     </s:states>
    
      <script>
       loadModule( Module_B.swf,) in to containerFor_B;
       someClickHandler() { currentState='ShowModule_B' }
      </script>
    
      <Group id="containerFor_A" includeIn="ShowModule_A" />
      <Group id="containerFor_B" includeIn="ShowModule_B" />
    
  10. Support Staff 10 Posted by Stray on 11 May, 2011 02:18 PM

    Stray's Avatar

    I'm guessing the children are being added / removed but the top level state isn't.

    Did you trace out to see whether preRemove is running?

  11. 11 Posted by Tony Smith on 11 May, 2011 03:25 PM

    Tony Smith's Avatar

    I am really sorry guys but something has ruined the test case. This might be related but let me know if it is new-thread worthy: Now my view isn't even registering at all. It calls the preRegister but not onRegister. If you have time, I would love to hear any ideas. Here are my trace statements as the module is loaded:

    Flex: Module Added to stage
    RL: ModuleMediator preRegister
    Flex: Module Initialized
    Flex: Module Creation Complete
    RL: ModuleMediator onRegister
    RL: ViewMediator preRegister
    Flex: View Added to stage
    Flex: View Initialized
    Flex: View Creation Complete

    ViewMediator:

       override public function onRegister():void
        {
            trace('RL: ViewMediator onRegister');
            /***********************************
             * view event listeners
             ***********************************/
    
            /***********************************
             * context event listeners
             ***********************************/
            eventMap.mapListener(eventDispatcher, GetShippingOptionsEvent.SHIPPING_OPTIONS, getShippingOptionsHandler);
            eventMap.mapListener(eventDispatcher, GetShippingOptionsEvent.SHIPPING_OPTIONS_COMPLETED, getShippingOptionsCompleteHandler);
    
        /***********************************
         * helper method callers
         ***********************************/
        }
    

    Yours truly,
    Frustrated

  12. Support Staff 12 Posted by Stray on 11 May, 2011 03:33 PM

    Stray's Avatar

    Have you checked the common problems list for mediators?

    The usual ones is Race conditions (mapping happening after the view hits the stage)

    I'm afraid I can't be any more helpful than that - I don't use flex because frankly I can code an AS3 view in my sleep and all that flex life-cycle stuff feels like a lot of complexity to trade for the simplest part of my work flow...!

    Hopefully some flex-dudes will be more forthcoming...

    Stray

  13. Support Staff 13 Posted by Stray on 11 May, 2011 03:35 PM

    Stray's Avatar

    BTW - the standard fix to the race conditions problem is to map your mediators from the inside outward. eg:

    mediatorMap.mapView(DeeplyNestedView, DeeplyNestedMediator);
    mediatorMap.mapView(NotSoDeeplyNestedView, NotSoDeeplyNestedMediator);
    // always last
    mediatorMap.mapView(MyContextView, MyContextMediator);
    

    Stray

  14. 14 Posted by Tony Smith on 11 May, 2011 03:59 PM

    Tony Smith's Avatar

    Ah, gotcha. I missed that one.

    Overall my current environment has lost its fricken mind. Restart actually fixed it the view registration. UHG!

    I see it!!
    OK, so if you happen to still be with me, here is the trace of me toggling between states. It looks like the module's mediator isn't reacting the same way as the other mediators when it is removed from the stage. What triggers preRemove()?

    LOAD MODULE
    Module Added to stage
    ModuleMediator preRegister
    Module Initialized
    Module Creation Complete
    ModuleMediator onRegister
    ViewMediator preRegister
    View Added to stage
    View Initialized
    View Creation Complete
    ViewMediator onRegister

    CHANGE STATE (HIDE MODULE)
    Module Removed to stage
    View Removed to stage
    ViewMediator preRemove

    CHANGE STATE (SHOW MODULE)
    Module Added to stage
    ViewMediator preRegister
    ViewMediator onRegister
    View Added to stage

    CHANGE STATE (HIDE MODULE)
    Module Removed to stage
    View Removed to stage
    ViewMediator preRemove

    CHANGE STATE (SHOW MODULE) Module Added to stage
    ViewMediator preRegister
    ViewMediator onRegister
    View Added to stage

  15. 15 Posted by Stray on 11 May, 2011 04:13 PM

    Stray's Avatar

    check out the mediatorMap on github.

    https://github.com/robotlegs/robotlegs-framework/blob/master/src/org/robotlegs/base/MediatorMap.as

    line 308 is where the view removal process starts.

    Essentially if the .stage property isn't null (of the view) then the 'remove' stuff doesn't happen.

    Stray

  16. 16 Posted by Tony Smith on 11 May, 2011 10:04 PM

    Tony Smith's Avatar

    I think I am going to close this thread and open a new one to see if I can get some feedback on using Flex 4 States. Having view mediators be destroyed and created every time their includeIn state is called is not good. :-(

  17. Tony Smith closed this discussion on 11 May, 2011 10:21 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac