10 Replies Latest reply on Jan 5, 2011 4:17 PM by D Baron

    Modules and Interfaces Issue

    D Baron Level 1

      Hi Folks,

       

      I am getting my feet wet in Flex, having just come from 10 years of ASP and C# web dev, and 10 years of VB dev before that. I am developing what will be a several-dozen 'page' app in Flex 4. My plan:  Main App contains 'viewstack' with 8 NavigatorContents.  As users use the app, I will dynamically load in a module into the appropriate 'slot' in the viewstack.  That module in turn will have its *own* viewstack, which can then load in its own modules.

       

      I have got some of the first 'layer' working, i.e., the main app, using ModuleManager, can load in and 'view' a specified module.  No interfaces were needed or used at this point.

       

      Now though, when Module_1 is trying to load (and use) Module_2, I need to use interfaces since I want Module_1 to be able to 'call methods' in Module_2.  I'd also like Module_2 to be able to raise events 'up' so that Module_1 can handle them, but that's another issue.. 

       

      In any case, I have created very simple 'test' modules just to get this working.  I have also created a simple interface for Module_2, and it is being implemented just fine (I believe).  The problem seems to be inside of Module_1.   I cannot seem to cast the instantiation of Module_2 to the interface that represents it.

       

      I have read many articles on modules and interfaces in the Docs/Adobe help.  I have scoured the Internet and read many posts that either repeat the Docs, or provide a small twist.  No matter what I do it does not seem to work.  I will be the first to admit that I may not have things 'set up' properly in my project.  For instance, all of my 'modules' are in the same 'package' as the main app.  Besides possibly defeating the purpose of 'smaller initial download size', am I shooting myself in the foot in some other way?

       

      Here is my code, simplified, with names changed for clarity:

       

      Main App mxml:  //this part works fine, no issues

      import mx.core.IVisualElement;
      import mx.events.ModuleEvent;
      import mx.modules.IModuleInfo;
      import mx.modules.ModuleManager;
      import businessLayer.Module_2_Interface;  //NOT SURE if I need to do this, since 'main' app doesn't 'use' Module 2
        
      public var _modInfo:IModuleInfo;

       

      private function loadModule_1():void {
      _modInfo = ModuleManager.getModule("Module_1.swf");
      _modInfo.addEventListener(ModuleEvent.READY, ModEventHandler);          
      _modInfo.load(null, null, null, moduleFactory);
      }
        
      private function ModEventHandler(e:ModuleEvent):void
      {
      myViewStack.addElement(_modInfo.factory.create() as IVisualElement);  //no problem here - Module 1 displays in viewstack great
      }

       

      Module_1 mxml:

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Module xmlns:fx="
      http://ns.adobe.com/mxml/2009"
           xmlns:s="library://ns.adobe.com/flex/spark"
           xmlns:mx="library://ns.adobe.com/flex/mx" layout="absolute" width="1000" height="407"
           creationComplete="loadList(0);">

      <fx:Script>
        <![CDATA[
         import businessLayer.Module_2_Interface;
        
         import mx.core.IVisualElement;
         import mx.events.ModuleEvent;
         import mx.modules.IModuleInfo;
         import mx.modules.ModuleManager;
        
         protected function loadList(whichType:Int):void
         {
          //begin the load process...
          _listModInfo = ModuleManager.getModule("Module_2.swf");
          _listModInfo.addEventListener(ModuleEvent.READY, listModEventHandler);          
          _listModInfo.load(null, null, null, moduleFactory);
         }
        
         private function listModEventHandler(e:ModuleEvent):void
         {
         // THIS is where the problems occur.  I cannot seem to cast the resultant module instance as my interface

          // I have tried numerous variations found in posts from the Internet and the Live Docs.  None work

          var modInstance:IVisualElement = _listModInfo.factory.create() as IVisualElement;  //this WORKS fine
          var disInstance:Object = _listModInfo.factory.create() as DisplayObject;  //this WORKS fine
          var listMod:Module_2_Interface = modInstance as Module_2_Interface;  //this produces NULL
          var eChild:Module_2_Interface= e.module.factory.create() as Module_2_Interface;  //this produces NULL

          var iChild:Module_2_Interface= _listModInfo.factory.create() as Module_2_Interface;  //this produces NULL
          navList.addElement(modInstance as IVisualElement);  //this WORKS, i.e., I can add the 'thing' to the
      viewstack

          //is THIS where I should 'cast/instantiate' the newly added object? Some other post said to do that

         }
        ]]>
      </fx:Script>


      <mx:ViewStack x="0" y="0" id="vstkTest" width="100%" height="405" borderVisible="false" selectedIndex="0">
        <s:NavigatorContent id="navList" width="100%" height="100%"></s:NavigatorContent>
        <s:NavigatorContent id="navDetail" width="100%" height="100%"></s:NavigatorContent>
      </mx:ViewStack>
      </mx:Module>

       

       

       

      Module_2 mxml:

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Module xmlns:fx="
      http://ns.adobe.com/mxml/2009"
           xmlns:s="library://ns.adobe.com/flex/spark"
           xmlns:mx="library://ns.adobe.com/flex/mx" layout="absolute" width="1000" height="407"
           implements="businessLayer.Module_2_Interface">

      <fx:Script>
        <![CDATA[
         public function getTest():int {
          return 5;
         }
        
         public function loadTest(whichData:String):void {
          //alert the type!;
         }
        ]]>
      </fx:Script>

      <s:TextInput left="100" top="200" />
      </mx:Module>

       

      Module_2_Interface.as:

      package businessLayer
      {
      import flash.events.IEventDispatcher;

      import mx.core.IVisualElement;

        //extends IEventDispatcher
      public interface Module_2_Interface extends IEventDispatcher {
        function getTest():int;
        function loadTest(friendType:String):void;
      }

      }

       

      ----------------------------------------------

      So... besides the question of "how can I instantiate/cast the module as the interface, I have a couple other questions:

       

      1.  ModuleLoader or ModuleManager?  Both seem to support an ActionScript driven model, and both seem to support 'status events' and such.  Why one over the other?

       

      2.  Where do module 'go'?  Seperate 'packages'?   Seperate 'folders'?

       

      Thanks in advance,

       

      -David

        • 1. Re: Modules and Interfaces Issue
          saisri2k2 Level 4

          did you try

           

           

          this.addElement((_listModInfo.factory.create() as secondmoduleInterface) as displayObject);

           

          ?

           

          also remove all the otr lines.. use only one line at a time.. modules can becme very dirty.. you need to handle them well.

           

           

           

          also why not load the 2nd module in the prent application(use some factory) and pass the ref to the child module? that way, there is only one guy maintaining all the modules..(just wondering if loading a module in a module might b a problem)

           

          also try secondmoduleInterface(_listModInfo.factory.create() )

           

          Message was edited by: saisri2k2

          • 2. Re: Modules and Interfaces Issue
            D Baron Level 1

            Your first suggestion,

            this.addElement((_listModInfo.factory.create() as secondmoduleInterface) as displayObject);... did not work.

             

            I did not notice the 2nd suggestion, and will try that later tonight.

             

            I *think* I am starting to see the problem/answer, but am not sure of the solution quite yet.

             

            There was another post about a similar issue... in that post a guy responded that the code could not get a 'handle' to the loaded module *until* it was 'added' into the visual component.  Most of the examples I have seen on this kind of stuff use a mx.moduleloader, directly 'on' the mxml (as opposed to actionscript).

            I have a mx:viewstack, but inside it are spark navigatorcontents.   All the examples, after 'loading' the mx:moduleLoader control, access that control's 'child' object, and then cast that child object as the interface type.   In my case, the spark navigatorContent does not have a 'child'.  I have tried the 'getElementAt(index) thing, but that seems to return individual 'controls' on the module, not the 'whole module'.

             

            So... I guess I am still at a loss... I guess I do not fully understand how the whole 'module loading thing' works.  I can easily 'load in' the module into the navigatorContent control.   I can even cast the 'loaded module' as a generic Object, and then make method calls on it - and they work!  However, this does not take into account the Interface, which is the way it *should* be done.

             

            I'll keep playing around... might try module loader instead of manager...

             

            -David

            • 3. Re: Modules and Interfaces Issue
              Flex harUI Adobe Employee

              I assume you've viewed the modules presentation on my blog.

               

              When modules load other modules you have to be very careful about the

              applicationDomain.  I don't think passing NULL will work.  I would try:

                  new ApplicationDomain(ApplicationDomain.currentDomain)

               

               

              --

              Alex Harui

              Flex SDK Team

              Adobe System, Inc.

              http://blogs.adobe.com/aharui

              • 4. Re: Modules and Interfaces Issue
                D Baron Level 1

                Hi Alex,

                 

                Yes, I have read your presentation.  From what I could tell, it was talking more about module loader (versus module manager) and was dealing more with "application loading module", versus "module loading module". 

                 

                I am not trying to 'pass' null anywhere.  I showed the 'null things' in my code just so you could see that trying to instantiate/cast the 'result' of the module load always comes back as NULL (with an error indicating that 'no such variable exists' - meaning the Module_2_Interface).

                 

                The basic gist is this:  I need Module_1 to load Module_2, and then be able to 'nicely' call methods and set properties via Module_2's interface.  I also have to 'put' Module_2 'into' the 'visual stuff' (view stack) of Module_1.   I am not sure of the 'order' of what to do, i.e., I know I 'load' the module first.  But then, do I 'addElement' to the view stack first, or try to instantiate (as a Module_2_Interface) the newly loaded Module_2, set some properties, call some methods and *then* addElement it to the view stack?   Or, do I do those last two steps in reverse?

                 

                I have seen your comments pertaining to the application domain thing, but have not understood 'where' it should go, based on my own constructs.  Using my code above in this thread, where do you propose putting that line?

                 

                You seem to have the biggest/best handle on modules and such... I tried to comment to your presentation two nights ago, but you have not responded yet.  This seems like an important 'concept' that should be very 'do-able' for medium to large projects.  I look forward to your response.

                 

                Thank you!

                 

                -David

                • 5. Re: Modules and Interfaces Issue
                  Flex harUI Adobe Employee

                  From your original post:

                   

                  protected function loadList(whichType:Int):void

                     {

                      //begin the load process...

                      listModInfo = ModuleManager.getModule("Module2.swf");

                      _listModInfo.addEventListener(ModuleEvent.READY, listModEventHandler);

                      _listModInfo.load(null, null, null, moduleFactory);

                     }

                   

                  Those are the nulls I'm referring to.

                   

                  The create() method should return a displayobject you can stick into a

                  viewstack.  Whether you call methods on it before or after is up to you.

                  • 6. Re: Modules and Interfaces Issue
                    D Baron Level 1

                    Thanks Alex, yes, I did not realize which NULLs you were referring to... The basic 'load module' code was literally copy/pasted directly out of the various Live Docs that I have read.  Since they seem to work (though not for this interface stuff) I never bothered to contemplate them.

                     

                    I will see if what you suggest helps/fixes the issue.

                     

                    In general though, would you say my 'structure' is correct and that I am 'close' to getting this to work?

                     

                    -David

                    • 7. Re: Modules and Interfaces Issue
                      Flex harUI Adobe Employee

                      I haven't looked at your code that carefully, but it appears that you have a

                      solid understanding of the general principles.  Once you get the

                      applicationDomains straightened out, it really does work like any other

                      abstraction and deferred loading technology.

                      • 8. Re: Modules and Interfaces Issue
                        D Baron Level 1

                        Thank you Alex, your suggestion worked great.

                         

                        My next challenge is to allow the 'parent' Module_1 listen for events coming out of its 'child' Module_2.  I see that Interfaces do not allow for defining events and such, but I am imagining that I can still dispatch an event from within Module_2 and 'handle it' within Module_1.   We'll see...  If it's as easy as doing the same with custom components, then this won't be much of an issue.

                         

                        Thanks again!

                         

                        -David

                        • 9. Re: Modules and Interfaces Issue
                          Flex harUI Adobe Employee

                          I'm pretty sure you can put event metadata on an interface, but it only

                          matters for MXML declarations anyway and with modules, you're doing

                          everything in AS.

                           

                          As long as the interface extends flash.events.IEventDispatcher, you can call

                          addEventListener on the module and get events dispatched from the module.

                          • 10. Re: Modules and Interfaces Issue
                            D Baron Level 1

                            Yes, you are correct.  I even created my own custom event so that I could pass some module/context-specific data along with the event.  That event gets attached to the module's instance and then is handled just fine from the 'outer' module.

                             

                            Thanks again, and, I sent you a private message asking some more about modules.

                             

                            -David