Flex 4.5 Not listening to custom event dispatched in custom AS class - actionscript-3

I have the following situation:
I have an event handler, that displays small messages in my application's statusbar.
These messages get passes through by dispatching events from custom components.
A simple message could be like "HTTP Error" or so.
Now, the main event listener, in the main application file, listens to the event dispatched by any custom component, but seems to refuse listening to events dispatched by custom AS classes.
Here is my code for the custom event:
package main.events
{
import flash.events.Event;
public class ShowNoticeEvent extends Event
{
public var message:String;
public static const SHOW_NOTICE:String = "showNotice";
public function ShowNoticeEvent(type:String, msg:String, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
this.message = msg;
}
override public function clone():Event
{
return new ShowNoticeEvent(type, message);
}
}
}
This is the event listener in the main application file:
addEventListener(ShowNoticeEvent.SHOW_NOTICE, showNoticeListener, true);
And this is the custom AS class that dispatches the custom event. I pasted all the code, so you could see the whole part of it.
package components.dashboard
{
import components.dashboard.models.*;
/* Event imports */
import flash.events.*;
import main.events.*;
import mx.controls.Alert;
import mx.core.UIComponent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
[Event(name="showNotice", type="main.events.ShowNoticeEvent")]
public class Controller extends UIComponent
{
private var baseUrl:String;
public function Controller(baseUrl:String)
{
this.baseUrl = baseUrl;
}
public function getRunningQuotations():void
{
var runningQuotationsList:RunningQuotationsList = RunningQuotationsList.getInstance();
execService("index.php?a=1", runningQuotationsList.updateList, "pnlRunningQuotations");
}
public function getRecentProjects():void
{
var recentProjectsList:RecentProjectsList = RecentProjectsList.getInstance();
execService("index.php?a=2", recentProjectsList.updateList, "pnlRecentProjects");
}
public function getLatestCustomers():void
{
var latestCustomersList:LatestCustomersList = LatestCustomersList.getInstance();
execService("index.php?a=3", latestCustomersList.updateList, "pnlLatestCustomers");
}
private function execService(url:String, listener:Function, component:String):void
{
var basicService:HTTPService = new HTTPService(baseUrl);
basicService.showBusyCursor = true;
basicService.addEventListener(FaultEvent.FAULT, function(e:FaultEvent):void{httpFault(e, component)});
basicService.method = "POST";
basicService.resultFormat = "text";
basicService.url = url;
basicService.addEventListener(ResultEvent.RESULT, listener);
basicService.send();
}
private function httpFault(event:FaultEvent, component:String = null):void {
var faultstring:String = event.fault.faultString;
var eventObj:ShowNoticeEvent = new ShowNoticeEvent(ShowNoticeEvent.SHOW_NOTICE, faultstring, true);
dispatchEvent(eventObj);
trace(faultstring);
}
}
}
So to sum it all up:
- The event listener listens to the custom event dispatched by any custom component.
- The event listener does not listen to the custom event duspatched by an AS class.
Those who wonder, the event really gets dispatched, that's why I added a trace call.

The instance of Controller Class would have to be added to stage for that to work.
by doing
addEventListener(ShowNoticeEvent.SHOW_NOTICE, showNoticeListener, true);
in the main file you are adding the listener to the stage.
So basically you are doing.
stage.addEventListener(ShowNoticeEvent.SHOW_NOTICE, showNoticeListener, true);
If controler instance is not on stage you won't see the event.
You might want to look into a Singleton type pattern for your data management as that would fit this setup pretty good.

Main:
Controller.getLastInstance().addEventListener(ShowNoticeEvent.SHOW_NOTICE, showNoticeListener, true)
.
package components.dashboard
{
import components.dashboard.models.*;
/* Event imports */
import flash.events.*;
import main.events.*;
import mx.controls.Alert;
import mx.core.UIComponent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
[Event(name="showNotice", type="main.events.ShowNoticeEvent")]
public class Controller extends UIComponent
{
static public function getLastInstance():Controller { return _instance; }
static private var _instance:Controller;
private var baseUrl:String;
public function Controller(baseUrl:String)
{
_instance = this;
this.baseUrl = baseUrl;
}
public function getRunningQuotations():void
{
var runningQuotationsList:RunningQuotationsList = RunningQuotationsList.getInstance();
execService("index.php?a=1", runningQuotationsList.updateList, "pnlRunningQuotations");
}
public function getRecentProjects():void
{
var recentProjectsList:RecentProjectsList = RecentProjectsList.getInstance();
execService("index.php?a=2", recentProjectsList.updateList, "pnlRecentProjects");
}
public function getLatestCustomers():void
{
var latestCustomersList:LatestCustomersList = LatestCustomersList.getInstance();
execService("index.php?a=3", latestCustomersList.updateList, "pnlLatestCustomers");
}
private function execService(url:String, listener:Function, component:String):void
{
var basicService:HTTPService = new HTTPService(baseUrl);
basicService.showBusyCursor = true;
basicService.addEventListener(FaultEvent.FAULT, function(e:FaultEvent):void{httpFault(e, component)});
basicService.method = "POST";
basicService.resultFormat = "text";
basicService.url = url;
basicService.addEventListener(ResultEvent.RESULT, listener);
basicService.send();
}
private function httpFault(event:FaultEvent, component:String = null):void {
var faultstring:String = event.fault.faultString;
var eventObj:ShowNoticeEvent = new ShowNoticeEvent(ShowNoticeEvent.SHOW_NOTICE, faultstring, true);
dispatchEvent(eventObj);
trace(faultstring);
}
}
}
Not Ideal since you could only ever have 1 of them.
But I think better than having to turn a simple EventDispatcher into DisplayObject and add it to stage just to Simply bubble.

Related

AS3: 1180 Call to a possibly undefined property: Add Child

Pretty big noob at AS3. I'm trying to Load a SWF into another file. (Main .fla loading external SWFS on mouse click)
I keep getting the error: 1180 Call to a possibly undefined property: Add Child, however.
My LoadSWF code is:
package {
import flash.display.*;
import flash.events.*;
import flash.net.*;
public class LoadSWF {
private var loaderFile: Loader;
private var swfFile: Object;
private var sourceFile: String;
private var fileLabel: String;
private var canDrag: Boolean;
private var popX: int;
private var popY: int;
public function LoadSWF(myFile: String, myLabel: String, myX: int = 0, myY: int = 0, myDrag: Boolean = false) {
// constructor code
trace("Loading SWF file:", myFile);
sourceFile = myFile;
fileLabel = myLabel;
canDrag = myDrag;
popX = myX;
popY = myY;
openSWF();
}
private function openSWF(): void {
// initialise variables
loaderFile = new Loader();
swfFile = addChild(loaderFile);
// set initial position of the SWF popup
loaderFile.x = popX;
loaderFile.y = popY;
try {
loaderFile.load(new URLRequest(sourceFile));
// runs after the SWF popup has finished loading
loaderFile.contentLoaderInfo.addEventListener(Event.COMPLETE, SWFloaded);
} catch (err: Error) {
// provide some error messages to help with debugging
trace("Error loading requested document:", sourceFile);
trace("Error:", err);
sourceFile = null;
}
} //end openSWF
private function SWFloaded(evt: Event): void {
// and add the required event listeners
loaderFile.addEventListener(MouseEvent.MOUSE_DOWN, dragSWF);
loaderFile.addEventListener(MouseEvent.MOUSE_UP, dropSWF);
// use the POPUP reference to access MovieClip content
swfFile.content.gotoAndStop(fileLabel);
// assigns a close function to the button inside the popup
swfFile.content.closeBtn.addEventListener(MouseEvent.CLICK, closeSWF);
// remove the COMPLETE event listener as it’s no longer needed
loaderFile.contentLoaderInfo.removeEventListener(Event.COMPLETE, SWFloaded);
} //end SWFLOaded
private function dragSWF(evt: MouseEvent): void {
swfFile.content.startDrag();
}
private function dropSWF(evt: MouseEvent): void {
swfFile.content.stopDrag();
}
private function closeSWF(evt: MouseEvent): void {
// remove the required event listeners first
loaderFile.removeEventListener(MouseEvent.MOUSE_DOWN, dragSWF);
loaderFile.removeEventListener(MouseEvent.MOUSE_UP, dropSWF);
swfFile.content.closeBtn.removeEventListener(MouseEvent.CLICK, closeSWF);
// remove the pop-up
loaderFile.unloadAndStop();
}
} //end class
} //end package
I'm calling it into my main class file, which code is (I left out the rest, guessing its unnecessary):
package {
import flash.display.MovieClip;
import flash.text.TextField;
import flash.display.SimpleButton;
import flash.utils.Dictionary;
import flash.text.TextFormat;
import flash.net.*;
import flash.events.*;
import fl.controls.*;
import flash.media.*;
import fl.events.ComponentEvent;
import fl.managers.StyleManager;
import fl.data.DataProvider;
import fl.data.SimpleCollectionItem;
import fl.managers.StyleManager;
import fl.events.ComponentEvent;
import flash.events.Event;
import flash.net.SharedObject;
import LoadSWF;
public class Main extends MovieClip {
//Declare variables
private var componentFmt: TextFormat;
private var radioBtnFmt: TextFormat;
private var playerData: Object;
private var savedGameData: SharedObject;
// Pop-up Variables
private var popupFile: LoadSWF;
private var swfPath: String;
public function Main() {
// constructor code
this.savedGameData = SharedObject.getLocal("savedPlayerData");
this.setComponents();
this.setPlayerData();
//this.swfPath = "";
//this.isHelpOpen = false;
//this.sndPath = "musicSFX/music2.mp3";
//this.isMuted = false;
//this.sndTrack = new LoadSND(this.sndPath, this.canRepeat);;
//this.muteBtn.addEventListener(MouseEvent.CLICK, this.setMute);
swfPath = "";
helpBtn.addEventListener(MouseEvent.CLICK, openSWF);
//hauntedForestBtn.addEventListener(MouseEvent.CLICK, openSWF);
}
public function openSWF(evt: MouseEvent): void {
// determine which button was pressed
var myFile: String = evt.currentTarget.name.replace("Btn", ".swf");
myFile = (swfPath == "") ? myFile : swfPath + myFile;
if (myFile == "help.swf") {
// load the help SWF file - is draggable
swfFile = new LoadSWF(myFile, currentFrameLabel, 80, 60, true);
} else {
// load the selected SWF file - is not draggable
swfFile = new LoadSWF(myFile, currentFrameLabel);
}
addChild(swfFile);
}
If anyone could help me find a solution, i'd greatly appreciate it.
Thanks :)
addChild is defined by DisplayObjectContainer.
So to access this function, you'll have to alter LoadSWF so that it extends DisplayObjectContainer.

Loading flex Modules from an XML file

I am trying to parse an xml file and load Flex modules dynamically in my application. But it loads only the last module everytime. I have a singleton class which does the parsing and loading of modules. Here is the class
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var _module:IModuleInfo;
private var _handler:Function;
private var loader:URLLoader;
public function VappModuleManager(object:SingletonEnforcer)
{
}
public function set handler(handler:Function):void
{
_handler=handler;
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
Alert.show("Event Completed");
var manifest:XML=new XML(event.target.data);
Alert.show(manifest.module.length());
for (var index:int=0;index<manifest.module.length();index++)
{
Alert.show(MODULE_PATH+manifest.module[index].#name);
_module=ModuleManager.getModule(MODULE_PATH+manifest.module[index].#name);
_module.addEventListener(ModuleEvent.READY,_handler);
_module.load();
}
}
}
}
internal class SingletonEnforcer {}
I use the above class as follows.
moduleManager=VappModuleManager.instance;
moduleManager.handler=myhandler;
moduleManager.load();
I understand the problem is with eventlistener for variable "_module" but dont know how to solve it. Any help appreciated.
The call to IModuleInfo.load is asynchronous so your for loop has run completely before any of the modules have loaded. Also, your class level _module property is overwritten by a new Module instance each time the loop iterates.
I'd suggest loading each module sequentially by waiting for the READY event and initiating the load of the next module only when it has fired. I'd also fire an event when all the modules are loaded instead of executing a callback function as this will give you more flexibility (multiple objects can listen for an event for example).
The following isn't tested, but should give you the idea:
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var loader:URLLoader;
private var manifest:XML;
private var loadCount:int = 0; // track loaded modules
public function VappModuleManager(object:SingletonEnforcer)
{
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
manifest =new XML(event.target.data);
// load the first module
loadModule();
}
private function loadModule() {
// Use a locally scoped variable to avoid writing over the previous instance each time.
// You could push these onto an array if you need to be able to access them later
var module:IModuleInfo = ModuleManager.getModule(MODULE_PATH+manifest.module[loadCount].#name);
module.addEventListener(ModuleEvent.READY, moduleReadyHandler);
module.load();
}
private function moduleReadyHandler(event:ModuleEvent) {
// Remove the event listener on the loaded module
IModuleInfo(event.target).removeEventListener(ModuleEvent.READY, moduleReadyHandler);
loadCount ++;
// Are there still modules in the manifest to load?
if (loadCount < manifest.module.length()) {
// Yes... load the next module
loadModule();
} else {
// No... we're all finished so dispatch an event to let subscribers know
dispatchEvent(new Event("complete"));
}
}
}
}

ActionScript - Access List/DataProvider From Custom CellRenderer

the code below sets up a List object in the main controller class that uses a custom cell renderer (CustomListCell class). the CustomListCell class creates a Button object for the cell that will be used to delete itself from the List's DataProvider.
how can i properly access the parent List object from its custom cell renderer?
//Controller Class
private function createList():void
{
provider = new DataProvider(data);
list = new List();
list.width = 200;
list.height = 400;
list.rowHeight = 50;
list.dataProvider = provider;
list.setStyle("cellRenderer", CustomListCell);
}
-----
//CustomListCell Class
import fl.controls.Button;
public class CustomListCell extends Sprite implements ICellRenderer
{
public function CustomListCell()
{
var button:Button = new Button();
button.label = "Delete Cell";
button.addEventListener(MouseEvent_MOUSE_DOWN, deleteCellHandler);
addChild(button);
}
private function deleteCellHandler(evt:MouseEvent):void
{
//Access List/DataProvider Here
}
//required implemented ICellRenderer functions follow
}
UPDATE
the following is my working custom renderer that implements ICellRenderer with Flash v3 List component. the List's dataProvider consists of 2 elements for each cell: randomColor and randomNumber.
package
{
//Imports
import fl.controls.Button;
import fl.controls.List;
import fl.controls.listClasses.ICellRenderer;
import fl.controls.listClasses.ListData;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.geom.ColorTransform;
//Class
public class TouchListRenderer extends Sprite implements ICellRenderer
{
//Properties
private var cellWidthProperty:Number;
private var cellHeightProperty:Number;
private var dataProperty:Object;
private var listDataProperty:ListData;
private var selectedProperty:Boolean;
//Cell Display Objects
private var backgroundCanvas:MySprite = new MySprite();
private var numberTextField:TextField = new TextField();
private var button:Button = new Button();
//Constructor
public function TouchListRenderer()
{
}
//Size Setter (Getter Functions Intentionally Omitted)
public function setSize(width:Number, height:Number):void
{
cellWidthProperty = width;
cellHeightProperty = height;
}
//Data Setter
public function set data(value:Object):void
{
dataProperty = value;
}
//Data Getter
public function get data():Object
{
return dataProperty;
}
//List Data Setter
public function set listData(value:ListData):void
{
listDataProperty = value;
}
//List Data Getter
public function get listData():ListData
{
return listDataProperty;
}
//Selected Setter
public function set selected(value:Boolean):void
{
selectedProperty = value;
layout();
}
//Selected Getter
public function get selected():Boolean
{
return selectedProperty;
}
//Size And Layout
private function layout():void
{
var newColor:ColorTransform = new ColorTransform();
newColor.color = dataProperty.randomColor;
backgroundCanvas.transform.colorTransform = newColor;
backgroundCanvas.scaleX = cellWidthProperty / backgroundCanvas.width;
backgroundCanvas.scaleY = cellHeightProperty / backgroundCanvas.height;
numberTextField.text = dataProperty.randomNumber;
numberTextField.autoSize = TextFieldAutoSize.LEFT;
numberTextField.textColor = 0xFFFFFF;
numberTextField.x = 50;
numberTextField.y = cellHeightProperty / 2 - numberTextField.height / 2;
numberTextField.border = true;
numberTextField.selectable = false;
button.label = "Delete";
button.x = cellWidthProperty - button.width - 50;
button.y = cellHeightProperty / 2 - button.height / 2;
button.drawNow();
button.addEventListener(MouseEvent.MOUSE_DOWN, buttonClickEventHandler);
addChild(backgroundCanvas);
addChild(numberTextField);
addChild(button);
}
//Button Click Event Handler
private function buttonClickEventHandler(evt:MouseEvent):void
{
List(listDataProperty.owner).removeItemAt(listDataProperty.index);
}
//Style Setter
public function setStyle(style:String, value:Object):void
{
}
//Mouse State Setter
public function setMouseState(state:String):void
{
}
}
}
package
{
import flash.display.Sprite;
public class MySprite extends Sprite
{
public function MySprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 10, 10);
graphics.endFill();
}
}
}
ugh! the answer was in front of me the whole time! next time remind me to check the docs:
List(listData.owner)
fl.controls.listClasses.ListData.owner
There are multiple ways to do this.
Here is a very hacky solution: Use an icon, and have that icon dispatch a close event.
The idea is you'll place a custom MovieClip in each list cell as icon. That icon will dispatch an event with the index of the cell clicked so you can remove it.
1st step: Make a basic custom event to pass cell index through:
package{
import flash.events.Event;
public class CloseEvent extends Event{
public static const CLOSE:String = 'close';
public var index:int;
public function CloseEvent(type:String,bubbles:Boolean = true,cancelable:Boolean=true){
super(type,bubbles,cancelable);
}
}
}
2nd step:: Draw a close icon or something, convert it to MovieClip and Export for Actionscript
3rd step: Add the event listener to dispatch the custom event when the close icon is clicked.
Inside the close icon Movie Clip I've placed the following actions:
import fl.controls.listClasses.CellRenderer;
//setup click
buttonMode = true;
if(parent) parent.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,dispatchClose);
//setup event
var closeEvent:CloseEvent = new CloseEvent(CloseEvent.CLOSE,true);
if(parent) closeEvent.index = CellRenderer(parent).listData.index;
//listen to click and pass on
function dispatchClose(event:MouseEvent):void {
dispatchEvent(closeEvent);
}
Very basic stuff, listen for mouse down, create an event and set the index and dispatch that event on click. The icon is added to a cell renderer, therefor the cell render is it's parent which it has a listData property among others, which holds the index of the cell.
So here's how the test snippet looks:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1),icon:Close});
ls.dataProvider = dp;
addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
ls.removeItemAt(event.index);
}
Since the CloseEvent bubbles, we can catch it from outside the cell renderer's icon and tell the list to remove the item at that index. It's possible to do that within the icon, but it will be necessary to 'climb' up the hierarchy all the way to the list, and it's pretty hacky already.
I did this because, I was probably as lazy as #TheDarkIn1978 :P to implement the ICellRenderer functions. Then I looked at question code again and didn't understand why the custom cell extends a Sprite, when CellRenderer already implements the ICellRenderer functions already.
So here is my attempt to do it in a less hacky manner:
package{
import fl.controls.*;
import fl.controls.listClasses.*;
import fl.data.*;
import flash.events.*;
public class SCListCell extends CellRenderer implements ICellRenderer{
protected var closeButton:Button;
protected var closeEvent:CloseEvent;
override protected function configUI():void {
super.configUI();
closeButton = new Button();
closeButton.label = 'x';
closeButton.buttonMode = true;
closeButton.setSize(30,20);
closeButton.drawNow();
closeButton.addEventListener(MouseEvent.CLICK,close);
addChild(closeButton);
closeEvent = new CloseEvent(CloseEvent.CLOSE);
}
private function close(event:MouseEvent):void{
closeEvent.index = listData.index;
dispatchEvent(closeEvent);
}
override protected function drawLayout():void{
mouseChildren = true;
closeButton.x = width-closeButton.width;
}
}
}
Used the same CloseEvent to pass the index, and the custom cell has direct access to the listData object to fetch the index, so the sample snippet looks like this:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;
addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
ls.removeItemAt(event.index);
}
ls.setStyle('cellRenderer',SCListCell);
So to answer your question:
how can i properly access the parent
List object from its custom cell
renderer?
You can use the listData property of the cell renderer.
You can if you want to, but it means going up a few levels:
package{
import fl.controls.*;
import fl.controls.listClasses.*;
import fl.data.*;
import flash.events.*;
public class SCListCell extends CellRenderer implements ICellRenderer{
protected var closeButton:Button;
override protected function configUI():void {
super.configUI();
closeButton = new Button();
closeButton.label = 'x';
closeButton.buttonMode = true;
closeButton.setSize(30,20);
closeButton.drawNow();
closeButton.addEventListener(MouseEvent.CLICK,close);
addChild(closeButton);
}
private function close(event:MouseEvent):void{
List(this.parent.parent.parent).removeItemAt(listData.index);
}
override protected function drawLayout():void{
mouseChildren = true;
closeButton.x = width-closeButton.width;
}
}
}
Which leaves the list creation part as simple as:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;
ls.setStyle('cellRenderer',SCListCell);
CloseEvent isn't needed in this case.
HTH

Getting data from custom classes (an OOP question)

How can I get some var / data from a custom classes?
The XML class
package classes
{
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
public class videoData extends MovieClip
{
private var myXML:XML;
private var myXMList:XMLList;
public function videoData()
{
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
}
private function processXML(e:Event):void
{
myXML = new XML(e.target.data);
myXMList = new XMLList(myXML.children());
}
public function getXML()
{
return myXML;
}
}
}
The class that is calling the XML
package classes
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import classes.videoData;
public class playList extends MovieClip
{
private var vData:videoData = new videoData();
public function playList()
{
trace(vData.getXML())
}
}
}
I would setup an event listener in 'playList' and dispatch an Event from 'videoData' once the XML has finished loading. That way you know when it's finished loading without using ENTER_FRAME (which will use alot more CPU as its checking every frame).
package classes
{
import flash.events.*;
import flash.display.MovieClip;
import classes.VideoData;
public class PlayList extends MovieClip
{
private var vData:VideoData;
public function PlayList()
{
vData = new VideoData();
vData.addEventListener(Event.COMPLETE, onXMLCompleteHandler);
}
private function onXMLCompleteHandler(e:Event):void
{
vData.removeEventListener(Event.COMPLETE, onXMLCompleteHandler);
trace(vData.getXML());
}
}
}
package classes
{
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
public class VideoData extends MovieClip
{
private var myXML:XML;
private var myXMList:XMLList;
private var myXMLLoader:URLLoader;
public function VideoData()
{
myXMLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
}
private function processXML(e:Event):void
{
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXML = new XML(e.target.data);
myXMList = new XMLList(myXML.children());
dispatchEvent(e);
}
public function getXML():XML
{
return myXML;
}
}
}
You should also ALWAYS capitalise your class names 'VideoData' not 'videoData'
You will need for the XML data to have been received before getting a value.
Add a private Boolean _xmlLoaded in your videoData class , set it to true in the processXML method.
Create a getter
public function get xmlLoaded():Boolean
{
return _xmlLoaded;
}
Now you can do this:
private var data:videoData = new videoData();
private var xmlData:XML;
private function init():void
{
addEventListener(Event.ENTER_FRAME , xmlLoaded );
}
private function xmlLoaded(event:Event):void
{
if( videoData.xmlLoaded )
{
xmlData = videoData.getXML();
removeEventListener(Event.ENTER_FRAME , xmlLoaded );
}
}
You are already getting your private myXML variable out through the .getXML() method. This is the best way to expose encapsulated data to outside classes.
An alternative would be to make your myXML field public instead of private, but using the get/set accessor methods you are hiding your actual implementation from outside world.
[Edit]
If your getXML() method is returning null, it means that your event handler (the processXML method) has not yet been called.
The problem appears to be in your VideoData constructor:
public function videoData()
{
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
}
The XML file is probably loaded before you attach the event handler, and that is why the event fires right before you start to listen to it. Try to reverse it and see if it works:
public function videoData()
{
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.addEventListener(Event.COMPLETE, processXML); // moved up
myXMLLoader.load(new URLRequest("playlist.xml"));
}

Override Clone() in custom event for AS3... need help

I have created a custom even class which is pretty basic. But when calling an event and then relaying that event to another class I have encountered the "cannot transform thisEvent into thisOtherEvent" error.
I realize this is because I needed to override the Clone function in my custom event like so:
package com
{
import flash.disply.*;
import flash.events.Event;
public class MyCustomEvents extends Event
{
public static const SOME_EVENT:String = "some_event";
public var info:Object;
public function MyCustomEvents($type:String, $info:Object,$bubbles:Boolean = false, $cancelable:Boolean = false)
{
super($type, $bubbles, $cancelable);
this.info = $info;
}
public override function clone():Event {
return new MyCustomEvents($type, $bubbles, $cancelable);
}
}
}
However I am still getting this error when I dispatch the event. Anything else I might be missing?
here is the error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.greensock.events::TransformEvent#d8df709 to com.customEvents.MyCustomEvents.
I tried casting the event in the code like so:
var deleteImgEvent:MyCustomEvent = new MyCustomEvent(MyCustomEvents.IMAGE_DELETE, {imgData: getImg}, true, false); this.dispatchEvent(deleteImgEvent as MyCustomEvents);
Still no luck.
UPDATE:
Ok, seems like the problem is in the greensock Transform library. When the event handler for my custom event is called, I run a function of the TransformManager class.
_manager.deleteSelection();
Inside that class it dispatched a TransformEvent. Not sure why, but it is reading that delete event as a MyCustomEvent.
/**
* #usage
* var myEvent:CustomEvent = new CustomEvent(CustomEvent.EVENT_TYPE_A, { integerRelatedToEvent: 5, stringRelatedToEvent: 'easy' });
* addEventListener(CustomEvent.EVENT_TYPE_A, traceCustomEvent);
* dispatch(myEvent);
* function traceCustomEvent ($e:CustomEvent):void {
* trace($e.type);
* }
*/
package {
import flash.events.Event;
public class CustomEvent extends Event {
// Types:
public static const EVENT_TYPE_A:String = 'CustomEvent.EVENT_TYPE_A';
public static const EVENT_TYPE_B:String = 'CustomEvent.EVENT_TYPE_B';
// Components:
private var _customDatum:Object;
public function get customDatum ():Object { return _customDatum; }
public function CustomEvent ($type:String, $customDatum:Object) {
super($type);
_customDatum = $customDatum;
}
public override function clone ():Event {
return new CustomEvent(type, _customDatum);
}
}
}
"When creating your own custom Event
class, you must override the inherited
Event.clone() method in order for it
to duplicate the properties of your
custom class. If you do not set all
the properties that you add in your
event subclass, those properties will
not have the correct values when
listeners handle the redispatched
event."
package com.events;
{
import flash.events.Event;
public class XMLLoaderEvent extends Event
{
public static const XML_LOADED:String = "XML_Loaded";
public var data:*;
public var properties:Object;
public function XMLLoaderEvent( type:String,_data:*,bubbles:Boolean = false,cancelable:Boolean = false):void
{
super( type, bubbles, cancelable );
data = _data;
}
// Override clone
override public function clone():Event
{
return new XMLLoaderEvent( type, data, bubbles, cancelable);
}
}
}
Don't know if that's it but you have an extra parameter $info:Object into your custom event, but you don't pass it in your clone contructor.
return new MyCustomEvents(type, info, bubbles, cancelable);
I think you need the clone function to return a MyCustomEvents type. Not an Event type. And you need to add the info parameter as stated by the previous poster.
package com {
import flash.display.*;
import flash.events.Event;
public class MyCustomEvents extends Event {
public static const SOME_EVENT:String = "some_event";
public var info:Object;
public function MyCustomEvents($type:String, $info:Object,$bubbles:Boolean = false, $cancelable:Boolean = false) {
super($type, $bubbles, $cancelable);
this.info = $info;
}
public override function clone():MyCustomEvents {
return new MyCustomEvents(this.type, this.info, this.bubbles, this.cancelable);
}
}
}