Monday, 16 August 2010

Cairngorm 3 Module Library

At work recently I have been looking at the Cairngorm 3 Module Library. It does some pretty cool things for example:

  • Skinnable ModuleLoader that displays loading and error states for a module
  • Lazy loads modules when parsley events are dispatched
  • Passes events to modules when they have loaded

The last item is what I was trying to get to work. We wanted to dispatch a loadSomeData event. The services that would load that data however are not initially available and need to be loaded in a module. Using a lazy load policy this module would be loaded and the event would then be passed to the module so that the loadSomeData Command would fire. Our CommandResult handler in the main application would then fire when the data had loaded.

To set this you need to set a few things up. You need a ParsleyModuleDescriptor in your application context:

<cairngorm:parsleymoduledescriptor
    url="SampleModule.swf"
    objectid="sampleModule"
    />

A lazy load policy in your context:

<cairngorm:LazyModuleLoadPolicy
    objectId="lazyLoadPolicy"
    type="{ ModuleInitialisationEvent }"
    />

And a ModuleViewLoader in your application:

<module:ModuleViewLoader
    moduleManager="{ moduleManager }"
    skinClass="{ ModuleViewLoaderSkin }"
    loadPolicy="{ lazyLoadPolicy }"
    />

This is enough to load the module when the ModuleInitialisationEvent is dispatched but the event will not be passed to the module as when the event is dispatched the module context is not yet initialised.

To solve this problem we need a ModuleMessageInterceptor tag, again in our application context:

<cairngorm:ModuleMessageInterceptor
    type="{ ModuleInitialisationEvent }"
    moduleRef="sampleModule"
    />

Now this should all work but as you can see from the sample app here it doesn’t. The module loads but the event does not get passed to the module (a working version of the sample app is here).

To fix this I had to patch the Cairngorm Module Library. There are actually 2 separate problems that I have reported in the 2 bugs listed here and here.

If you want to get your lazy loading modules to work correctly without patching Cairngorm then you need to make sure that your messageHandler or Command in the module is locally scoped. This does however mean that global CommandResult handlers won’t work for any results from the call.

You also need to make sure that your ModuleViewLoader has a moduleID and that your initialisation event has the same moduleId in and has the ModuleId Meta Data Tag.

I hope that my 2 patches for these fixes will be incorporated into trunk soon so that they will be available without patches.

3 comments:

  1. Based on a discussion on a thread here:

    http://www.spicefactory.org/forum/viewtopic.php?t=866

    The patch for the first bug (CGM-34) is probably not a good idea as other global handlers would get the event twice. I'm not sure if it is possible to fix this.

    ReplyDelete
  2. Hi Roaders,
    Thank you for the sample, that's great!

    In your sample you only have one module, so the code
    [Inject]
    Bindable]public var moduleManager : IModuleManager;
    only have one possibility. That's ok.

    But if I have more than one module: Is it possible (at runtime) to get one of the modules defined in the context and display it's content?.
    For exemple: Can I have a textbox and load dynamically the module typed in the textbox?.

    I don't want use something like that
    [Inject(id="expensesModule")]
    I want to decide wich module to show dinamically

    Thank you!
    s2o

    ReplyDelete