The Blog

AS3 ModuleLoader and ModuleManager CSS

While programming in Flex 4.5, I came across an issue that took forever to figure out. It had to do with the ModuleLoader class and the inability of it to inherit styles from the application that was loading it.

According to Flex documentation, a Module that is loaded into the same application domain as it’s parent container should inherit the styles of the application. In that way, you should be able to create an application, set some style sheets for it, then load modules that inherit them.

I know there’s something to be said about StyleManagers in Flex 4.5; according to some documentation I’ve read, it appears that all applications and modules have their own implementation of the StyleManager whereas in previous versions of Flex, the StyleManager was a Singleton and globally applied to all applications and modules; but I don’t really understand the implementation of it as much as I would like.

That being said, I’m left to implementation, testing and debugging.

ModuleLoader

In my application, I referenced my style sheet using the fx:Style tag near the top of my MXML document:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:mx="library://ns.adobe.com/flex/mx"
  xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  width="1040" height="100%" 
  creationComplete="onCreation()" 
  initialize="onInit()"
  name="My Application">

<fx:Style source="resource/style.css" />
...

Next, I imported my ModuleLoader class and declared a private instance of it:

<fx:Script>
<![CDATA[
  ...
  import mx.modules.ModuleLoader;
  private var _myModuleLoader:ModuleLoader;
  private var _myModule:Module;
  ...

Later on, I setup the code that loads my module and handles the ModuleEvent.READY event.

  ...
  _myModuleLoader.url = 'path/to/MyModule.swf';
  _myModuleLoader.addEventListener(ModuleEvent.READY,onModuleReady); 
  _myModuleLoader.loadModule();
  
  private function onModuleReady(e:ModuleEvent):void
  {
    _myModule = (e.target.child as Module);
    this.addElement(_myModule );
  }
  ...

this.addElement(_myModule )

When I would add _myModule to the application via the addElement() command, it would add the Module, but would NOT apply any of the application styles to it. I tested it by adding some button styles to the application container. The button styles applied to all buttons in the application container, but to none in _myModule.

After a lot of testing, I found that if I added the _myModuleLoader to my application as an MXML component, it would actually inherit the styles. So, rather than declare _myModuleLoader as a private variable in the fx:Script area, I placed it down in the MXML/View code:

    ...
    <ms:ModuleLoader id="_myModuleLoader" />
  </s:Application>

This allowed my to keep most of my code the same, with the exception that _myModuleLoader was added as MXML rather than declared as pure actionscript. As to why this works, I’m not sure. My guess is that it has something to do with the way the MXML is compiled with the ModuleLoader rather than executing it at runtime. For some reason, the addElement() command isn’t sending the styles to the Module it adds.

ModuleManager

Alternatively, while I was working on the ModuleLoader issues, I found that the ModuleManager worked similar to the ModuleLoader, and made it possible to add Modules; modules with inherited styles; to the application.

First off, I altered my code to accommodate the ModuleManager:

<fx:Script>
<![CDATA[
  //import mx.modules.ModuleLoader;
  import mx.modules.ModuleManager;
  import mx.modules.IModuleInfo;
  import mx.modules.Module;

  private var _myModuleLoader:IModuleInfo;
  private var _myModule:Module;
  ...
  ...
  //_myModuleLoader.url = 'path/to/MyModule.swf';
  _myModuleLoader = ModuleManager.getModule('path/to/MyModule.swf');
  _myModuleLoader.addEventListener(ModuleEvent.READY,onModuleReady); 
  //_myModuleLoader.loadModule();
  _myModuleLoader.load(null,null,null,this.moduleFactory);
  
  private function onModuleReady(e:ModuleEvent):void
  {
    //_myModule = (e.target.child as Module);
    _myModule = _myModuleLoader.factory.create() as Module;
    this.addElement(_myModule);
  }
  ...

ModuleLoader.load()

The key to making this work is the ModuleLoader.load() command. It takes in arguments that deal with application and security domains. These can remain as null, except for the fourth argument: the ModuleFactory. This needs the same ModuleFactory that the application uses and lets the module know who its parent style manager is.

If anyone out there knows how to use ModuleLoader in combination with addElement(), keeping the styles of the application container, it would be greatly appreciated.

Tags: , , ,

No comments yet.

Leave a Comment

Remember to play nicely folks, nobody likes a troll.

You must be logged in to post a comment.