15 Replies Latest reply on Oct 28, 2009 2:41 PM by Flex harUI

    Menubar load modules for each sub-menu

    ajdove

      I am creating an application using the MENUBAR but cannot get a module to open when a sub-menu is clicked. I have stripped my app down to bare bones to eliminate other factors. The menubar has several main options, such as, Button1, Button2, Button3 and then each has a sub-menu dropdown. If Button1 has Button1Sub1 and Button1Sub2 dropdowns I want to have a different module launch when either of the sub-menus are clicked.

       

      I have been successful in using ModuleManager to open a particular module referencing the creationComplete="moduleLoadHandler()" but not by selecting a menu item from the menubar. My application needs to be as user-friendly and Windows-like as possible. There are many different modules which need to be loaded and unloaded.

       

      I have attached a screenshot image of my project tree and circled the ActionModule.swf file to show its location.

      I have attached my code below:

       

      <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="creationHandler();" >

       

          <mx:Script>

              <![CDATA[

                  import mx.controls.menuClasses.IMenuBarItemRenderer;

                  import mx.controls.MenuBar;

                  import mx.controls.menuClasses.MenuBarItem;

       

                  import mx.controls.Alert;

      import mx.modules.Module;

      import mx.events.ModuleEvent;

      import mx.modules.ModuleManager;

      import mx.modules.IModuleInfo;

       

      import mx.rpc.events.ResultEvent;

      import mx.rpc.events.FaultEvent;

      import mx.events.FlexEvent;

      import mx.events.MenuEvent;

                  import mx.collections.*;

       

                  public var _moduleInfo:IModuleInfo;

       

       

                  [Bindable]

                  public var menuBarCollection:XMLListCollection;

       

                  private var menubarXML:XMLList =

                      <>

                          <menuitem label="Menu1" data="top">

                              <menuitem label="MenuItem 1-A" data="1A" itemClick="moduleLoadHandler()"/>

                              <menuitem label="MenuItem 1-B" data="1B"/>

                          </menuitem>

                          <menuitem label="Menu2" data="top">

                              <menuitem label="MenuItem 2-A" type="check"  data="2A"/>

                              <menuitem type="separator"/>

                              <menuitem label="MenuItem 2-B" >

                                  <menuitem label="SubMenuItem 3-A" type="radio"

                                      groupName="one" data="3A"/>

                                  <menuitem label="SubMenuItem 3-B" type="radio"

                                      groupName="one" data="3B"/>

                              </menuitem>

                          </menuitem>

                          <menuitem label="Menu3" data="top">

                              <menuitem label="MenuItem 3-A" data="3A"/>

                              <menuitem label="MenuItem 3-B" data="3B"/>

                          </menuitem>

                          <menuitem label="Menu4" data="top">

                              <menuitem label="MenuItem 4-A" data="4A"/>

                              <menuitem label="MenuItem 4-B" data="4B"/>

                          </menuitem>                                       

                      </>;

       

       

                  private function creationHandler():void{

      menuBarCollection = new XMLListCollection(menubarXML);

       

      }

       

      private function moduleLoadHandler(event:ModuleEvent ):void{

       

      canvas.addChild( _moduleInfo.factory.create() as Module );

      _moduleInfo = ModuleManager.getModule('ActionModule.swf');

      _moduleInfo.addEventListener(ModuleEvent.READY, moduleLoadHandler);

      _moduleInfo.load();

      }

       

       

                  // Event handler for the MenuBar control's itemClick event.

                  private function menuHandler(event:MenuEvent):void  {

                      // Don't open the Alert for a menu bar item that

                      // opens a popup submenu.

                      //if (event.item.@data != "top") {

                      //    Alert.show("Label: " + event.item.@label + "\n" +

                      //        "Data: " + event.item.@data, "Clicked menu item");

                      //}

       

                  }

       

                  private function onTopSelection(event:MenuEvent):void{

                      var mb:MenuBar=event.target as MenuBar;

                      var selectedIndex:int=mb.selectedIndex;

       

                      for (var i:int=0;i<mb.menuBarItems.length;i++){

                          if(i==selectedIndex){

                              (mb.menuBarItems[i] as MenuBarItem).setStyle("fontWeight","bold");                   

                          }

                          else{

                              (mb.menuBarItems[i] as MenuBarItem).setStyle("fontWeight","normal");                           

                          }

                      }

                  }

       

               ]]>

          </mx:Script>

       

          <mx:Canvas id="canvas" height="75%" width="75%"

              paddingTop="10" paddingLeft="10">

       

              <mx:MenuBar labelField="@label" itemClick="menuHandler(event);" dataProvider="{menuBarCollection}" change="onTopSelection(event)" />

       

          </mx:Canvas>

      </mx:Application>

        • 1. Re: Menubar load modules for each sub-menu
          Flex harUI Adobe Employee

          A module takes at least one frame to load so it will never be available on the next line after the load call.

           

          I don't understand why you need your sub-menus in modules.  I'd try pre-loading the modules or maybe just the XML that represents the data.

           

          Another trick might be to have built-in submenus that say "loading..." so those show immediately, then see if you can find a way to replace the items in that sub-menu when the module finishes loading.

           

          Alex Harui

          Flex SDK Developer

          Adobe Systems Inc.

          Blog: http://blogs.adobe.com/aharui

          • 2. Re: Menubar load modules for each sub-menu
            ajdove Level 1

            Oh no. There's a misunderstanding. I want to have the menubar in the root application and then be able to load other modules when I click on a menu item. Each sub-menu will load a different module. Is this not a good practice? Having each portion of the application separated into modular units? For instance: Sales, Order Entry, Inventory, Accounts Rec., Accounts Pay, etc. Each one would be a different module and accessed from the menubar.

             

            Do you have a better suggestion for organizing a business application? Or even navigating the application? I am trying to have the application function like a normal Windows application with its menu and drop-down navigation.

             

            Thanks

            Alex

            • 3. Re: Menubar load modules for each sub-menu
              Flex harUI Adobe Employee

              Oh, sorry.  Thought you wanted the submenu's to come from modules.

               

              Breaking a large app into modules is the recommended practice. 

               

              In your code the moduleLoadHandler looks suspicious.  It looks like your ready handler is calling the moduleLoadHandler again.

               

              I would expect the menu XML to contain the URLs of the module you wish to load, and maybe an mx:ModuleLoader whose url is set by the itemClick event.

               

              Alex Harui

              Flex SDK Developer

              Adobe Systems Inc.

              Blog: http://blogs.adobe.com/aharui

              • 4. Re: Menubar load modules for each sub-menu
                ajdove Level 1

                Ummmm...so you are saying that the XML menus can contain the ModuleLoader functions to call the swf files directly?  If so, could you write an example with my code?

                 

                Would it look like this?

                 

                <menuitem label="Menu1" data="top">
                     <menuitem label="MenuItem 1-A" data="1A" itemClick="moduleLoader('ActionModule.swf')"/>
                     <menuitem label="MenuItem 1-B" data="1B"/>
                </menuitem>

                 

                And I would eliminate the extra code inside this function to look like this:

                 

                private function moduleLoadHandler(event:ModuleEvent ):void{
                canvas.addChild( _moduleInfo.factory.create() as Module );
                }

                 

                Would this be correct?

                 

                Alex

                • 5. Re: Menubar load modules for each sub-menu
                  Flex harUI Adobe Employee

                  No, the menu data would just contain the url.

                   

                   

                   

                   

                  And loadThisModule would look something like:

                   

                  function loadThisModule(event:MenuEvent):void

                  {

                       moduleLoader.url = event.item.@url;

                  }

                   

                   

                  Alex Harui

                  Flex SDK Developer

                  Adobe Systems Inc.

                  Blog: http://blogs.adobe.com/aharui

                  1 person found this helpful
                  • 6. Re: Menubar load modules for each sub-menu
                    ajdove Level 1

                    I almost have it...I have done what I believe you told me to do. I get bad results but no errors thought. Instead of having the ActionModule.swf file load when the menu item is clicked it is currently loading automatically on the application load event. Why?  I only want it to work when I click the sub-menu.

                     

                    Here is my updated code below with updated written in bold text. I commented out the entire function moduleLoadHandler.:

                     

                     

                    import mx.modules.ModuleLoader;

                     

                    <menuitem label="Menu1" data="top">

                    <menuitem label="MenuItem 1-A" data="ActionModule.swf" click="loadThisModule()"/>

                    <menuitem label="MenuItem 1-B" data="1B"/>

                    </menuitem>

                     

                    private function loadThisModule(event:MenuEvent):void

                    {

                    var url:String = moduleLoader.url;

                    var moduleUrl:String;

                    if( url == moduleUrl ) return;

                    if( url != null ) moduleLoader.unloadModule();

                        moduleLoader.url = event.item.@url;

                    }

                     

                     

                    private function moduleLoadHandler(event:ModuleEvent ):void{

                     

                    // canvas.addChild( _moduleInfo.factory.create() as Module );

                    // _moduleInfo = ModuleManager.getModule('ActionModule.swf');

                    // _moduleInfo.addEventListener(ModuleEvent.READY, moduleLoadHandler);

                    // _moduleInfo.load();

                    }

                     

                    <mx:Canvas id="canvas" height="75%" width="75%"

                            paddingTop="10" paddingLeft="10">

                    <mx:ModuleLoader id="moduleLoader" url="ActionModule.swf"/>

                            <mx:MenuBar labelField="@label" itemClick="menuHandler(event);" dataProvider="{menuBarCollection}" change="onTopSelection(event)" />

                    </mx:Canvas>

                    • 7. Re: Menubar load modules for each sub-menu
                      Flex harUI Adobe Employee

                      In your moduleLoader tag, you specified the url to be ActionModule.swf so it will load that module right away.  I recommended leaving it blank and setting it in your menu event handler.

                       

                      Alex Harui

                      Flex SDK Developer

                      Adobe Systems Inc.

                      Blog: http://blogs.adobe.com/aharui

                      • 8. Re: Menubar load modules for each sub-menu
                        ajdove Level 1

                        I seem to continue digging myself deeper and deeper into a state of confusion. Your answers are helpful, but they appear to lead me to a place slightly out of reach of the full answer yet far enough away where I cannot fill in the gaps. I love learning but I am struggling at this. I am really trying to grasp this solution. Would it be possible to show me what you are trying to tell me in code.

                         

                        Your last comments suggested I remove the URL from the moduleLoader tag which I have completed. Now, as you suggested, the alternate module does not load right away. This is good. Thanks. Now, however, I still cannot get the alternate module to load on the event handler of the menu item.

                         

                        Your recommendation was to set the alternate module URL in the menu event handler. I understand this comment to be referencing the following code:

                         

                        <menuitem label="Menu1" data="top">

                        <menuitem label="MenuItem 1-A" data="ActionModule.swf"/>

                        <menuitem label="MenuItem 1-B" data="1B"/>

                        </menuitem>

                         

                        I believe the correct event handler for the sub-menu item is the itemClick="" attribute.  If so, I still do not know how to write the code inside the event handler to make the alternate module display.

                         

                        What about the rest of my code? Is it written correctly to make my alternate module load on clicking the sub-menu? Or are there other obstacles I need to fix?

                         

                        Again, thank you for your help. I look forward to realizing the solution and learning from this.

                         

                        Alex

                        • 9. Re: Menubar load modules for each sub-menu
                          Flex harUI Adobe Employee

                          I think it should look like:

                           

                          function menuHandler(event:MenuEvent):void

                          {

                               moduleLoader.url = event.item.@data

                          }

                           

                          Alex Harui

                          Flex SDK Developer

                          Adobe Systems Inc.

                          Blog: http://blogs.adobe.com/aharui

                          • 10. Re: Menubar load modules for each sub-menu
                            ajdove Level 1

                            Yaaaaaaahhhoooooo!

                             

                            This worked perfectly. Thank you for detailing your explanations for me. It was a great help. My light bulb turned on when I saw your "@data" in that it is referencing an attribute like a variable. Why I didn't see this before boggles me too. I will implement this example into my project for all of my sub-menu items.

                             

                            Thank you again.

                            Regards,

                             

                            Alex D.

                            • 11. Re: Menubar load modules for each sub-menu
                              Mugunda

                               

                              Hi,

                                 I am also doing the same way, but ended up with some issues.

                              I have a Main Application with a menu Bar on Top and Rest of the area occupied by a ModuleLoader.

                               

                              First I set the URL to login module, on successful login I initialize my menu Bar based on User role and load a new module, it contains only a SuperTabNavigator.

                              On click of an item in my Application Menu, I add a Custom Componenet built on Canvas (Named MyCanMod , this contains a Module loader and a progress bar in it , I have attached the code) as a tab to the tab navigator.

                               

                              On menu item click, I take the data of my menu item and set that as the URL of my Module Loader inside the Custom canvas. Then it is added as a tab to my tab navigator.

                                    private function openItem(event:MenuEvent):void

                               

                                          {

                              var myModule:MyCanMod = new MyCanMod();                tabNav.addChild(myModule);

                                              tabNav.selectedChild = myModule;

                                              myModule.label = event.item.@label;

                                              myModule.icon = document_icon;

                                              myModule.urlParam = event.item.@module;

                               

                                          }

                              urlParam is a bined to the module Loader url in my Custom componenet.

                              All works fine.  I am not unloading any modules and all the module loader are set to current domain.

                              When the user logs out and logs back with out refreshing the browser I get Type Error or some time null Object error and it is random. If I refresh the browser and login back, every thing is fine.

                              I do have reference for IDragManager,HistoryManager,PopUpManager,RemoteObject in main application.

                               

                              I am not concerned about unloading modules now, but then on Tab close event I unloaded the module, and that did not solve the problem.

                               

                               

                              I get an error like

                              TypeError: Error #1034: Type Coercion failed: cannot convert flexlib.controls::PromptingTextInput@6152a851 to flexlib.controls.PromptingTextInput.

                                          at mx.core::UIComponent/createReferenceOnParentDocument()

                                          at mx.core::Container/createComponentFromDescriptor()

                                          at mx.core::Container/createComponentsFromDescriptors()

                                          at mx.core::Container/createChildren()

                                          at mx.core::UIComponent/initialize()

                                          at mx.core::Container/initialize()

                                          at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()

                                          at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::childAdded()

                                          at mx.core::Container/addChildAt()

                                          at mx.core::Container/addChild()

                               

                               

                              Any help is appreciated; I am really struck with it, please help.

                              • 12. Re: Menubar load modules for each sub-menu
                                Mugunda Level 1

                                Hi,

                                 

                                 

                                  I Added a reference to the promtingText Input in main application and it id did not throw any error,   So I assume it is code sharing problem.

                                 

                                I am using flexlib.swc, but I have not configured it as RSL, I think that would be the correct solution, instead of adding refrence to all componenets.

                                 

                                Am i correct or is there some thing wrong which I am doing.

                                • 13. Re: Menubar load modules for each sub-menu
                                  Flex harUI Adobe Employee

                                  If you use FlexLib.swc as an RSL every class in it will get loaded.  Depending on what percentage of those classes you are using that may be inefficient, but should work.

                                   

                                  Alex Harui

                                  Flex SDK Developer

                                  Adobe Systems Inc.

                                  Blog: http://blogs.adobe.com/aharui

                                  • 14. Re: Menubar load modules for each sub-menu
                                    Mugunda Level 1

                                    So If I dont want to add it as RSL then I need to create a reference for all the required Class in my Application.mxml ?

                                    • 15. Re: Menubar load modules for each sub-menu
                                      Flex harUI Adobe Employee

                                      Yes or add the list to a -config.xml file that uses the mxmlc -includes option.  See Flex 4's BasicTest-config.xml for an example.

                                       

                                      Alex Harui

                                      Flex SDK Developer

                                      Adobe Systems Inc.

                                      Blog: http://blogs.adobe.com/aharui

                                      1 person found this helpful