flexunit of handle customer event and Async.asyncHandler() - apache-flex

Any one know how does Async.asyncHandler() work and if Async.processOnEvent() can only used in [Before] method.(Any one know some helpful document besides http://docs.flexunit.org/).
I define a MXML component named HelloCompo(extends Vbox), and the component define a function named hello(), in the hello() dispacthed a customer event named HelloEvent(the event type just named "hello"), and in another function named init() listened for the event, I want to test whether the event is dispatched properly or not. So I have the test following:
var helloCompo = new HelloCompo();
helloCompo.hello();
helloCompo.addEventListener("hello", Async.asyncHandler(this, handleHello, 1000, null, handleTimeOut));
The test will always excute the handleTimeOut method(means the HelloEvent is not dispatched, but when helloCompo.hello() excute, it really dispacthed, so what's going wrong?)

package flexUnitTests
{
import flash.events.Event;
import org.flexunit.asserts.assertTrue;
import org.flexunit.asserts.fail;
import org.flexunit.async.Async;
public class HelloTest
{
private var helloCompo:HelloCompo;
[Before]
public function setUp():void
{
helloCompo = new HelloCompo();
}
[After]
public function tearDown():void
{
helloCompo = null;
}
[Test(async)]
public function testHello():void
{
var handler:Function = Async.asyncHandler(this, helloHandler, 300, null, helloFailed);
helloCompo.addEventListener("hello", handler);
helloCompo.hello();
}
private function helloHandler(event:Event, passThroughObject:Object):void
{
//assert somthing
}
private function helloFailed(event:Event, passThroughObject:Object):void
{
fail("hello not dispatched");
}
}
}
HelloCompo.as
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class HelloCompo extends EventDispatcher
{
public function HelloCompo(target:IEventDispatcher=null)
{
super(target);
}
public function hello():void
{
dispatchEvent(new Event("hello"));
}
}
}

I think you need to add your event listener before calling hello() actually

Related

AS3: Event dispatching via dispatchEvent- pass params?

I would like to dispatch an event from my class along with a url.
I know that I can do the following:
import flash.events.EventDispatcher;
private function thumbClick(e:MouseEvent):void
{
dispatchEvent(new Event("clicked"));
}
But I don't know how I would send params along with the event...?
Also, in my main app runner, I try:
var my_ev:Event = new Event("clickedImage");
my_ev.hasOwnProperty(e.currentTarget.link);
dispatchEvent(my_ev);
...but I'm not sure that this would be the correct syntax.
Thanks for any help,
jml
Allan is correct, you will want to make a custom event. Couple of things to note:
import flash.events.Event;
public class ThumbnailEvent extends Event
{
public static var THUMB_CLICKED:String = "thumbClicked";
private var _url:String;
public function get url():String { return _url }
public function ThumbnailEvent (type:String, url:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type,bubbles,cancelable);
_url = url
}
override public function clone():Event
{
return new ThumbnailEvent(type, url, bubbles, cancelable);
}
}
Custom events need to always override clone. If the event is bubbled or relayed in anyway it needs this method. Custom properties should be private with a read-only getter. This is a standard convention to prevent the alteration of properties throughout the life of the event.
Using this approach would change your code to:
private function thumbClick(e:MouseEvent):void
{
dispatchEvent(new ThumbnailEvent(ThumbnailEvent.THUMB_CLICKED, myUrlString));
}
//elsewhere
addEventListener(ThumbnailEvent.THUMB_CLICKED, thumbClickedHandler);
private function thumbClickedHandler(event:ThumbnailEvent):void
{
var link:String = event.url;
}
Custom Event tutorial at adobe.com
I just make a custom event class.
import flash.events.Event;
public class ThumbnailEvent extends Event
{
public static var THUMB_CLICKED:String = "thumbClicked";
public var url:String;
public function ThumbnailEvent (type:String,url:String)
{
super(type);
this.url = url
}
}
and then use it like:
var thumbEvent:ThumbnailEvent = new ThumbnailEvent(ThumbnailEvent.THUMB_CLICKED,"myURL");
dispatchEvent(thumbEvent);

Querying the state of a class's listener

I have instantiated a class (class1) that loads some data via PHP in an AS3 Flex project.
I instantiate class1, which is asynchronous and utilizes a URLLoader() to obtain its data.
Then I would like to instantiate class2, which needs to USE the data from class1, but when I simply instantiate it I find that class1's instance variable is not populated yet because I am calling class2 too quickly.
How can I create such a dependency that will link correctly?
I am really new to using listeners, but I am imagining a listener in class2 might be what I need?
Or maybe I can pass a reference to the listener in class1 into class2?
I also know nothing about dispatching events... is this the key?
Here's an example in pseudo code:
var class1:myC1 = new myC1("http://some/url/to/utilize");
//this never shows up because it hasn't loaded at the time i request it
trace("the stuff from class1 is: ", class1.myXMLList);
//and of course i can't use it here either
var class2:myC2 = new myC2(0x000000, class1.myXMLList);
Thanks for any help,
jml
Based on your question, I'm posting this "pseudo code" hopping it will help
package {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.*;
public class Class1 extends EventDispatcher {
private var _loader:URLLoader;
public var data:XMLList;
public function Class1(url:String) {
_loader = new URLLoader();
_loader.addEventListener(Event.COMPLETE, completeHandler);
// rest of the code here ....
_loader.load(new URLRequest(url));
}
protected function completeHandler(event:Event):void {
data = new XMLList(_loader.data); // probably wrong but
// I figured you had already
// implemented this part
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
I figured class 2 might look like this
package {
public class Class2 {
// your stuff here
public function Class2(color:uint, data:XMLList) {
}
}
}
The main class
package {
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite {
public var c1:Class1;
public var c2:Class2;
public function Main() {
c1 = new Class1("http://some/url/to/utilize");
c1.addEventListener(Event.COMPLETE, completeHandler);
}
protected function completeHandler(event:Event):void {
c2 = new Class2(0xffcc00, c1.data);
}
}
}
Hope this helps
If you want Flex/FlashBuilder to autocomplete the events for your classes, you can use the "Event" metadata tag before your class definition. Based on the example above, it would look like this
package {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.*;
// use the "Event" metadata tag
[Event(name="complete", type="flash.events.Event")]
public class Class1 extends EventDispatcher {
private var _loader:URLLoader;
public var data:XMLList;
public function Class1(url:String) {
_loader = new URLLoader();
_loader.addEventListener(Event.COMPLETE, completeHandler);
// rest of the code here ....
_loader.load(new URLRequest(url));
}
protected function completeHandler(event:Event):void {
data = new XMLList(_loader.data);
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
Now FlexBuilder/FlashBuilder should "autocomplete" the events for that class.
The downside is that you can't use "constants" with the "Event" metadata tag so this :
[Event(name=Event.COMPLETE, type="flash.events.Event")]
wouldn't work.
You can read more about event/event dispatching here.
Hope that helps :)

make cairngorm commands ALWAYS work synchronously

I see the benefit of asynchronous commands (waiting for server responses...) but in my flex app it creates me more problem than anything. Here's what I want:
EVERY command executes only after the previous one returned (to result or fault function)
And I'd like to do this as easily as possible.. by the way the GUI must become irresponsive (maybe a wait message) while a long command is being executed (I could show the wait message in the execute function and remove it in the fault or result function..)
any Idea?
I accomplished this by extending the CairngormEvent Class and adding two properties:
package control.events
{
import com.adobe.cairngorm.control.CairngormEvent;
public class AbstractCairngormEvent extends CairngormEvent
{
public var successHandler:Function;
public var failureHandler:Function;
public function AbstractCairngormEvent(type:String)
{
super(type);
}
}
}
And creating a new Class as a base for all Commands, which implements ICommand:
package control.commands
{
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import control.events.AbstractCairngormEvent;
/* This class is a base for all Commands. It allows the user to set callback
functions for successful completion and/or failure of the Command logic (i.e.
a WebService call). */
public class CairngormCommand implements ICommand
{
private var successHandler:Function;
private var failureHandler:Function;
public function execute(event:CairngormEvent):void
{
if (event is AbstractCairngormEvent)
{
var commandEvent:AbstractCairngormEvent =
event as AbstractCairngormEvent;
successHandler = commandEvent.successHandler;
failureHandler = commandEvent.failureHandler;
}
}
public function notifyCallerOfSuccess():void
{
if (successHandler != null)
successHandler.call(this);
}
public function notifyCallerOfFailure():void
{
if (failureHandler != null)
failureHandler.call(this);
}
}
}
Then in each Command Class, when the necessary logic is complete, or there is an error/failure, I call the appropriate function in the CairngormCommand base Class. Here is an example:
// Something like this would be in your view:
private function callSomeWebService():void {
var event:WebServiceEvent = new WebServiceEvent();
myEvent.successHandler = callMyEventSuccessHandler;
myEvent.failureHandler = callMyEventFailureHandler;
}
private function callMyEventSuccessHandler():void {
Alert.show("SUCCESS!!!");
}
private function callMyEventFailureHandler():void {
Alert.show("FAILURE!!!");
}
// Here is the Event in your Controller:
package control.events
{
import control.events.AbstractCairngormEvent;
public class WebServiceEvent extends AbstractCairngormEvent
{
public static var EVENT_ID:String = "webService";
public function WebServiceEvent()
{
super(EVENT_ID);
}
}
}
// And here is the Command in your Controller:
package control.commands
{
import com.adobe.cairngorm.control.CairngormEvent;
import control.commands.CairngormCommand;
import control.events.WebServiceEvent;
public class WebServiceCommand extends CairngormCommand
{
override public function execute(event:CairngormEvent):void
{
super.execute(event);
... // Call WebServices
}
...
private function webServiceResultHandler():void
{
// Handle results
...
notifyCallerOfSuccess();
}
private function webServiceFaultHandler():void
{
// Handle fault
...
notifyCallerOfFailure();
}
}
}
I use this EXCLUSIVELY in my Cairngorm applications now. The best part is, if you don't need to have a callback for success and/or failure, you can just leave those properties out of the event instantiation and simply dispatch the event.
Example of loading data needed for display before the display is loaded:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
usePreloader="false" initialize="initializeHandler();">
<mx:Script>
<![CDATA[
import control.events.InitializeApplicationEvent;
private function initializeHandler():void
{
initializeApplication();
}
private function initializeApplication():void
{
var event:InitializeApplicationEvent =
new InitializeApplicationEvent();
event.successHandler = initializationSuccessHandler;
event.dispatch();
}
private function initializationSuccessHandler():void
{
applicationContainer.visible = true;
}
]]>
</mx:Script>
<control:Services xmlns:control="control.*" />
<control:Controller xmlns:control="control.*" />
<view:ApplicationContainer xmlns:view="view.*" id="applicationContainer"
width="100%" height="100%" visible="false" />
</mx:Application>
InitializeApplicationCommand (notice how you can chain the events and callers as many times as you'd like):
package control.commands
{
import com.adobe.cairngorm.control.CairngormEvent;
import control.events.GetEvenMoreDataEvent;
import control.events.GetSomeDataEvent;
import control.events.GetSomeMoreDataEvent;
import control.events.InitializeApplicationEvent;
public class InitializeApplicationCommand extends CairngormCommand
{
override public function execute(event:CairngormEvent):void
{
super.execute(event);
getSomeData();
}
private function getSomeData():void
{
var event:GetSomeDataEvent = new GetSomeDataEvent();
event.successHandler = getSomeMoreData;
event.failureHandler = errorHandler;
event.dispatch();
}
private function getSomeMoreData():void
{
var event:GetSomeMoreDataEvent = new GetSomeMoreDataEvent();
event.successHandler = getEvenMoreData;
event.failureHandler = errorHandler;
event.dispatch();
}
private function getEvenMoreData():void
{
var event:GetEvenMoreDataEvent = new GetEvenMoreDataEvent();
event.successHandler = notifyCallerOfSuccess;
event.failureHandler = errorHandler;
event.dispatch();
}
private function errorHandler():void
{
alert.show("error");
}
}
}

Flex 3 Customevent not getting dispatched

I have a function called DrawPlaybook which listens to two events, one mouseclick event and one custom event.
public function DrawPlaybook(...):void
{
//...... other stuff
panel.addEventListener(MouseEvent.CLICK,
function(e:MouseEvent){onClickHandler(e,this.panel)});
panel.addEventListener(CustomPageClickEvent.PANEL_CLICKED,
onCustomPanelClicked);
}
I am planning to call the custom event from within "onClickHandler" like this:
public function onClickHandler(e:MouseEvent,panel):void
{
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
dispatchEvent(eventObj);
}
private function onCustomPanelClicked(e:CustomPageClickEvent):void {
Alert.show("custom click");
}
And here is the class definition for CustomPageClickEvent:
package
{
import flash.events.Event;
import mx.containers.Panel;
public class CustomPageClickEvent extends Event
{
public var panelClicked:Panel;
// Define static constant.
public static const PANEL_CLICKED:String = "panelClicked";
public function CustomPageClickEvent(type:String){
super(type);
//panelClicked = panel;
}
// Override the inherited clone() method.
override public function clone():Event {
return new CustomPageClickEvent(type);
}
public function getPanelSource():Panel{
return panelClicked;
}
}
}
The issue is that "onCustomPanelClicked" never gets invoked at all. Please let me know if you notice anything that I missed.
It's because you have registered the event listener for CustomPageClickEvent on the Panel, but you're dispatching it from DrawPlaybook
Just change this:
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
dispatchEvent(eventObj)
to this:
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
panel.dispatchEvent(eventObj)
... or change the event listener to this.addEventListener(CustomPageClickEvent.PANEL_CLICKED,
onCustomPanelClicked);.
Let me know if that works.

Custom Event Not Captured- why?

I am having a problem where I dispatch a custom event but the listener does not receive it (i.e. myHandler() in the code below). If I put everything in one mxml file, it works. When I separate the responsibilities in to separate classes, it fails. It is not clear to me what I am missing.
Any help you be appreciated.
Here is my code (update() in ViewModel.as is the entry point):
ChangeEvent.as
import flash.events.Event;
public class ChangeEvent extends Event
{
public function ChangeEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
// Set the new property.
this.isEnabled = isEnabled;
}
// Define static constant.
public static const ENABLE_CHANGED:String = "enableChanged";
// Define a public variable to hold the state of the enable property.
public var isEnabled:Boolean;
// Override the inherited clone() method.
override public function clone():Event {
return new ChangeEvent(type, isEnabled);
}
}
Model.as
public class Model extends EventDispatcher
{
private function TriggerEvent():void
{
var eventObj:ChangeEvent = new ChangeEvent(ChangeEvent.ENABLE_CHANGED);
dispatchEvent(eventObj);
}
}
ViewModel.as
public class ViewModel
{
import mx.controls.Alert;
import ChangeEvent;
private var model:Model;
public function ViewModel()
{
model = new Model();
addEventListener(ChangeEvent.ENABLE_CHANGED, myHandler);
}
public function update():void {
model.LoadData();
}
private function myHandler(event:Event):void {
Alert.show("An event occurred.");
}
}
Do I have to 'register' the event in ViewModel.as similar to the metadata tag in mxml?
e.g.
[Event(name="enableChange", type="ChangeEvent")]
You have to add the event listener on the model object (since it is the one dispatching the event).
model = new Model();
model.addEventListener(ChangeEvent.ENABLE_CHANGED, myHandler);
Hope that helps.

Resources