Using ModuleLoader events

The ModuleLoader class triggers several events, including setup, ready, loading, unload, progress, error, and urlChanged. You can use these events to track the loading process, and find out when a module has been unloaded or when the ModuleLoader target URL has changed.

The following example uses a custom ModuleLoader component. This component reports all the events of the modules as they are loaded by the main application.

Custom ModuleLoader:

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- modules/CustomModuleLoader.mxml -->
<s:ModuleLoader 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns="*" 
    creationComplete="init()">
    
  <fx:Script>
    <![CDATA[
        import mx.core.UIComponent;
    
        public var standin:UIComponent;

        public function init():void {
            addEventListener("urlChanged", onUrlChanged);
            addEventListener("loading", onLoading);
            addEventListener("progress", onProgress);
            addEventListener("setup", onSetup);
            addEventListener("ready", onReady);
            addEventListener("error", onError);
            addEventListener("unload", onUnload);

            standin = panel;
            removeElement(standin);        
        }

        public function onUrlChanged(event:Event):void {
            if (url == null) {
                if (contains(standin))
                    removeElement(standin);
            } else {
                if (!contains(standin))
                    addElement(standin);
            }
            progress.indeterminate=true;
            unload.enabled=false;
            reload.enabled=false;
        }

        public function onLoading(event:Event):void {
            progress.label="Loading module " + url;
            if (!contains(standin))
                addElement(standin);

            progress.indeterminate=true;
            unload.enabled=false;
            reload.enabled=false;
        }

        public function onProgress(event:Event):void {
            progress.label="Loaded %1 of %2 bytes...";
            progress.indeterminate=false;
            unload.enabled=true;
            reload.enabled=false;
        }

        public function onSetup(event:Event):void {
            progress.label="Module " + url + " initialized!";
            progress.indeterminate=false;
            unload.enabled=true;
            reload.enabled=true;
        }

        public function onReady(event:Event):void {
            progress.label="Module " + url + " successfully loaded!";
            unload.enabled=true;
            reload.enabled=true;

            if (contains(standin))
                removeElement(standin);
        }

        public function onError(event:Event):void {
            progress.label="Error loading module " + url;
            unload.enabled=false;
            reload.enabled=true;
        }

        public function onUnload(event:Event):void {
            if (url == null) {
                if (contains(standin))
                    removeElement(standin);
            } else {
                if (!contains(standin))
                    addElement(standin);
            }
            progress.indeterminate=true;
            progress.label="Module " + url + " was unloaded!";
            unload.enabled=false;
            reload.enabled=true;
        }
    ]]>
  </fx:Script>

  <s:Panel id="panel" width="100%" title="Status &amp; Operations">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    <mx:ProgressBar width="100%" id="progress" source="{this}"/>
    <s:HGroup width="100%">
      <s:Button id="unload" label="Unload Module" click="unloadModule()"/>
      <s:Button id="reload" label="Reload Module" click="unloadModule();loadModule()"/>
    </s:HGroup>
  </s:Panel>
</s:ModuleLoader>

Main application:

<?xml version="1.0"?>
<!-- modules/EventApp.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns="*"> 

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
            [Bindable]
            public var selectedModule:Object;
        ]]>
    </fx:Script>

    <s:ComboBox width="215" labelField="label" prompt="Select Coverage" 
        close="selectedModule=ComboBox(event.target).selectedItem">
        <s:dataProvider>
            <s:ArrayCollection>
                <fx:Object label="Life Insurance" 
                    module="insurancemodules/LifeInsurance.swf"/>
                <fx:Object label="Auto Insurance" 
                    module="insurancemodules/AutoInsurance.swf"/>          
                <fx:Object label="Home Insurance" 
                    module="insurancemodules/HomeInsurance.swf"/>
            </s:ArrayCollection>
        </s:dataProvider>
    </s:ComboBox>

    <s:Panel width="100%" height="100%" title="Custom Module Loader">
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout>
        <CustomModuleLoader id="mod" width="100%" url="{selectedModule.module}"/>
    </s:Panel>
    <s:HGroup>
        <s:Button label="Unload" click="mod.unloadModule()"/> 
        <s:Button label="Nullify" click="mod.url=null"/>
    </s:HGroup>  
</s:Application>

The insurance modules used in this example are simple forms, such as the following:

<?xml version="1.0" encoding="utf-8"?>
<!-- modules/insurancemodules/AutoInsurance.mxml -->
<s: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"
    backgroundColor="#ffffff" 
    width="100%" height="100%">
    <s:Label x="147" y="50" text="Auto Insurance" 
        fontSize="28" fontFamily="Myriad Pro"/>
    <s:Form left="47" top="80">
        <s:FormHeading label="Coverage"/>
        <s:FormItem label="Latte Spillage">
            <s:TextInput id="latte" width="200"/>
        </s:FormItem>
        <s:FormItem label="Shopping Cart to the Door">
            <s:TextInput id="cart" width="200"/>
        </s:FormItem>
        <s:FormItem label="Irate Moose">
            <s:TextInput id="moose" width="200"/>
        </s:FormItem>
        <s:FormItem label="Color Fade">
            <mx:ColorPicker/>
        </s:FormItem>
    </s:Form>
</s:Module>

Using the error event

The error event gives you an opportunity to gracefully fail when a module does not load for some reason. In the following example, you can load and unload a module by using the Button controls. To trigger an error event, change the URL in the TextInput control to a module that does not exist. The error handler displays a message to the user and writes the error message to the trace log.

<?xml version="1.0"?>
<!-- modules/ErrorEventHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx">

    <s:layout> 
        <s:VerticalLayout
                paddingTop="10" 
                paddingLeft="10" 
                paddingRight="10" 
                paddingBottom="10"/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.events.ModuleEvent;
        import spark.modules.ModuleLoader;
        import spark.modules.Module;
        import mx.controls.Alert;
        
        private function errorHandler(e:ModuleEvent):void {
            Alert.show("There was an error loading the module." + 
                " Please contact the Help Desk.\n" + 
                e.errorText);
        }
  
        public function createModule():void {
            if (chartModuleLoader.url == ti1.text) {
                /* If they are the same, call the loadModule() method. */
                chartModuleLoader.loadModule();
            } else {
                /* If they are not the same, then change the url, 
                   which then triggers a call to the loadModule() method. */
                chartModuleLoader.url = ti1.text;
            }
        }
        
        public function removeModule():void {
            chartModuleLoader.unloadModule();
        }
        ]]>
    </fx:Script>

    <s:Panel title="Module Example" height="90%" width="90%">
        <s:layout> 
            <s:VerticalLayout/>
        </s:layout>
        <s:HGroup>
            <s:Label text="URL:"/>
            <s:TextInput width="200" id="ti1" text="ColumnChartModule.swf"/>
            <s:Button label="Load" click="createModule()"/>
            <s:Button label="Unload" click="removeModule()"/>
        </s:HGroup>
        <s:ModuleLoader id="chartModuleLoader" error="errorHandler(event)"/>
    </s:Panel>
</s:Application>

Using the progress event

You can use the progress event to track the progress of a module as it loads. When you add a listener for the progress event, Flex calls that listener at regular intervals during the module’s loading process. Each time the listener is called, you can look at the bytesLoaded property of the event. You can compare this to the bytesTotal property to get a percentage of completion.

The following example reports the level of completion during the module’s loading process. It also produces a simple progress bar that shows users how close the loading is to being complete.

<?xml version="1.0"?>
<!-- modules/SimpleProgressEventHandler.mxml -->
<s:Application 
    creationComplete="initApp()"
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.events.ModuleEvent;
        import flash.events.ProgressEvent;
        import spark.modules.Module;
        import spark.modules.ModuleLoader;
        
        [Bindable]
        public var progBar:String = "";
        [Bindable]
        public var progMessage:String = "";
        
        private function progressEventHandler(e:ProgressEvent):void {
            progBar += ".";
            progMessage = 
                "Module " +  
                Math.round((e.bytesLoaded/e.bytesTotal) * 100) + 
                "% loaded";
        }

        public function initApp():void {
            chartModuleLoader.url = "ColumnChartModule.swf";     
        }

        public function createModule():void {
            chartModuleLoader.loadModule();
        }
        
        public function removeModule():void {
            chartModuleLoader.unloadModule();
            progBar = "";
            progMessage = "";
        }
        ]]>
    </fx:Script>

    <s:Panel title="Module Example" height="90%" width="90%">        
        <s:layout> 
            <s:VerticalLayout
                paddingTop="10" paddingLeft="10" 
                paddingRight="10" paddingBottom="10"/> 
        </s:layout>

        <s:HGroup>
            <s:Label id="l2" text="{progMessage}"/>
            <s:Label id="l1" text="{progBar}"/>
        </s:HGroup>  

        <s:Button label="Load" click="createModule()"/>
        <s:Button label="Unload" click="removeModule()"/>

        <s:ModuleLoader id="chartModuleLoader" 
            progress="progressEventHandler(event)"/>
    </s:Panel>    
</s:Application>

You can also connect a module loader to a ProgressBar control. The following example creates a custom component for the ModuleLoader that includes a ProgressBar control. The ProgressBar control displays the progress of the module loading.

<?xml version="1.0"?>
<!-- modules/MySimpleModuleLoader.mxml -->
<s:ModuleLoader 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[        
            private function clickHandler():void {
                if (!url) { 
                    url="ColumnChartModule.swf"; 
                } 
                loadModule();
            }        
        ]]>
    </fx:Script>

    <mx:ProgressBar id="progress" width="100%" source="{this}"/>
    <s:HGroup width="100%">
      <s:Button id="load" label="Load" click="clickHandler()"/>
      <s:Button id="unload" label="Unload" click="unloadModule()"/>
      <s:Button id="reload" label="Reload" click="unloadModule();loadModule();"/>
    </s:HGroup>
</s:ModuleLoader>

You can use this module in a simple application, as the following example shows:

<?xml version="1.0"?>
<!-- modules/ComplexProgressEventHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:local="*">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <s:Panel title="Module Example" height="90%" width="90%">        
        <s:layout> 
            <s:VerticalLayout 
                paddingTop="10" paddingLeft="10" 
                paddingRight="10" paddingBottom="10"/> 
        </s:layout>
        <s:Label text="Use the buttons below to load and unload the module."/>
        <local:MySimpleModuleLoader id="customLoader"/>
    </s:Panel>
    
</s:Application>

This example does not change the ProgressBar label property for all events. For example, if you load and then unload the module, the label property remains at "LOADING 100%". To adjust the label properly, you must define other event handlers for the ModuleLoader events, such as unload and error.