Can any one give me a simple example on how to dispatch an event in actionscript3 with an object attached to it, like
dispatchEvent( new Event(GOT_RESULT,result));
Here result is an object that I want to pass along with the event.
In case you want to pass an object through an event you should create a custom event. The code should be something like this.
public class MyEvent extends Event
{
public static const GOT_RESULT:String = "gotResult";
// this is the object you want to pass through your event.
public var result:Object;
public function MyEvent(type:String, result:Object, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.result = result;
}
// always create a clone() method for events in case you want to redispatch them.
public override function clone():Event
{
return new MyEvent(type, result, bubbles, cancelable);
}
}
Then you can use the code above like this:
dispatchEvent(new MyEvent(MyEvent.GOT_RESULT, result));
And you listen for this event where necessary.
addEventListener(MyEvent.GOT_RESULT, myEventHandler);
// more code to follow here...
protected function myEventHandler(event:MyEvent):void
{
var myResult:Object = event.result; // this is how you use the event's property.
}
This post is a little old but if it can help someone, you can use DataEvent class like so:
dispatchEvent(new DataEvent(YOUR_EVENT_ID, true, false, data));
Documentation
If designed properly you shouldn't have to pass an object to the event.
Instead you should make a public var on the dispatching class.
public var myObject:Object;
// before you dispatch the event assign the object to your class var
myObject = ....// whatever it is your want to pass
// When you dispatch an event you can do it with already created events or like Tomislav wrote and create a custom class.
// in the call back just use currentTarget
public function myCallBackFunction(event:Event):void{
// typecast the event target object
var myClass:myClassThatDispatchedtheEvent = event.currentTarget as myClassThatDispatchedtheEvent
trace( myClass.myObject )// the object or var you want from the dispatching class.
Related
Is there any simple -- or suggested -- way in order to send a parameter along with a custom event? Or even just a way to pass variables between two classes?
My program is a sort of simple Civ/Age of Empires kind of game, where you can place buildings on tiles. This would work as follows:
Player clicks on the icon on the HUD, which creates an dispatches an event which is received by the PLAYER class.
The PLAYER class changes a value depending on which building is held (clicked on).
Player clicks on the tile in the grid to place it, which dispatches an event which is received by the PLAYER class.
The PLAYER class creates a building object and adds it to an array within the PLAYER class.
An example of how I'd want the code to work:
icon.as
private function onMouseClick(e:MouseEvent = null):void {
var iconClickedEvent:Event = new Event("BUILDING_HELD", buildingType); // passes "buildingType" through the event somehow
stage.dispatchEvent(iconClickedEvent);
}
tile.as
private function onMouseClick(e:MouseEvent = null):void {
var buildingPlacedEvent:Event = new Event("BUILDING_PLACED", xRef, yRef);// passes "xRef" & "yRef", the tile's co-ordinate
stage.dispatchEvent(buildingPlacedEvent);
}
player.as
private function init(e:Event):void {
stage.addEventListener("BUILDING_HELD", buildingHeld(buildingType));
stage.addEventListener("BUILDING_PLACED", placeBuilding(xRef, yRef));
}
private function buildingHeld(building:int):void {
buildingType = building;
}
private function placeBuilding(xRef:int, yRef:int):void {
switch(buildingType){
case 1: // main base
MainBaseArray.push();
MainBaseArray[length-1] = new MainBase(xPos, yPos); // create new object with the references passed
break;
}
}
The best way to manage this is to create custom event classes for each of your events (or event types).
If you create a class that inherit Event, it will be usable in the same ways that a standard Event, but can contain custom values or methods.
Here's an example of such class :
public class BuildingEvent extends Event {
// contains an event name. Usefull to ensure at compile-time that there is no mistape in the event name.
public static const BUILDING_HELD:String = "BUILDING_HELD";
private var _buildingType:int;
// the constructor, note the new parameter "buildingType". "bubbles" and "cancelable" are standard parameters for Event, so I kept them.
public function BuildingEvent(type:String, buildingType:int, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
_buildingType = buildingType;
}
// using a getter ensure that a listening method cannot edit the value of buildingType.
public function get buildingType() {
return _buildingType;
}
}
We can then use this class like this :
// to dispatch the event
private function onMouseClick(e:MouseEvent = null):void {
var iconClickedEvent:BuildingEvent = new BuildingEvent(BuildingEvent.BUILDING_HELD, buildingType);
stage.dispatchEvent(iconClickedEvent);
}
// to listen to the event
private function init(e:Event):void {
stage.addEventListener(BuildingEvent.BUILDING_HELD, buildingHeld);
}
private function buildingHeld(event:BuildingEvent):void {
buildingType = event.buildingType;
}
I want to dispatch an Event 2 times:
I have a MainClass, a SecondClass and a ThirdClass.
In the ThirdClass, there's a clickEvent. I dispatch it to the SecondClass:
this.addEventListener(MouseEvent.CLICK, clickHandler);
public static const CLICKED_HANDLER:String = "clickedHandler";
public function clickHandler(e:MouseEvent):void {
dispatchEvent(new Event(CLICKED_HANDLER));
}
I catch and throw it in the SecondClass:
object.addEventListener(ThirdClass.CLICKED_Handler, clickedEventListener);
public static const CLICKED_HANDLER:String = "clickedHandler";
public function clickedEventListener(e:Event):void {
dispatchEvent(new Event(CLICKED_HANDLER));
}
And this I catch in the MainClass:
object.addEventListener(SecondClass.CLICKED_HANDLER, clickedEventListener);
public function clickedEventListener(e:Event):void {
trace("click");
}
But it wouldn't work... What am I doing wrong?
And how could I get information about the object of the ThirdClass that's clicked?
(Normaly with 1 dispatchEvent, it's with:
var thirdClassObject:ThirdClass = e.currentTarget as ThirdClass;
in the clickHandler method, but how to do this with 2 dispatchEvents?)
So: I want to know in my MainClass which ThirdClass-object is clicked.
Thanks a lot!
When you dispatch an event, the target property references the dispatcher.
What you apparently need is passing a reference to third class along with the event to use in the event handler of main class.
You have several options to achieve this.
If a dispatcher instance is on the display list, use event bubbling to handle events in parent display objects. Refer to the second argument of Event constructor and Event.bubbles property. This way you can subscribe to any events of child objects in a parent, and check Event.target property in your event handler. Most of mouse events like MouseEvent.CLICK are bubbling by default. So you could just listen to them and check targets in main class.// inside MainClass
// notice: we are subscribing to MainClass instance
this.addEventListener(MouseEvent.CLICK, clickedEventListener);
public function clickedEventListener(e:MouseEvent):void {
trace(e.target); // the target is what was actually clicked
// you may also notice the difference between e.target and e.currentTarget
}
If you still want to use CLICKED_HANDLER event, you may do so as follows:// inside ThirdClass
dispatchEvent(new Event(CLICKED_HANDLER, true));
// ---------------------------------------^
Remember: this will only work for display list members.
See the Event flow article on adobe.com.
Create a custom event class and place reference there. (And you can also use event bubbling with custom event classes.) This way you will dispatch your event as// inside SecondClass
public function clickedEventListener(e:Event):void {
var customEvent:CustomEventClass = new CustomEventClass(CLICKED_HANDLER);
customEvent.customTarget = e.target;
dispatchEvent(customEvent);
}
// inside MainClass
public function clickedEventListener(e:CustomEventClass):void {
trace(e.customTarget );
}
First, define what do you mean by "it wouldn't work..."?
Does the SecondClass receive the event at all? If so, you may try this:
//SecondClass
public function clickedEventListener(e:Event):void {
dispatchEvent(e);
}
//MainClass
object.addEventListener(ThirdClass.CLICKED_HANDLER, clickedEventListener);
Since when using sql lite if you try and do a function at the same moment it throws an error, im just trying to make a function that will check if its executing, and if it is try again in 10 milliseconds, this exact function works fine if i dont have to pass any arguments to the function but im confused how I can pass the vars back into the function it'll be executing.
I want to do:
timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));
But it will only allow me to do:
timer.addEventListener(TimerEvent.TIMER, saveChat);
It gives me this compile error:
1067: Implicit coercion of a value of
type void to an unrelated type
Function
How can I get this to pass this limitation?
Here's what I've got:
public function saveChat(username:String, chatBoxText:String, e:TimerEvent=null):void
{
var timer:Timer = new Timer(10, 1);
timer.addEventListener(TimerEvent.TIMER, saveChat);
if(!saveChatSql.executing)
{
saveChatSql.text = "UPDATE active_chats SET convo = '"+chatBoxText+"' WHERE username = '"+username+"';";
saveChatSql.execute();
}
else timer.start();
}
A function called by a listener can only have one argument, which is the event triggering it.
listener:Function — The listener function that processes the event.
This function must accept an Event
object as its only parameter and must
return nothing, as this example
shows:
function(evt:Event):void
Source
You can get around this by having the function called by the event call another function with the required arguments:
timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
saveChat(arg, arg, arg);
}
function saveChat(arg1:type, arg2:type, arg3:type):void
{
// Your logic.
}
Another thing you can do create a custom event class that extends flash.events.Event and create properties that you need within.
package
{
import flash.events.Event;
public class CustomEvent extends Event
{
// Your custom event 'types'.
public static const SAVE_CHAT:String = "saveChat";
// Your custom properties.
public var username:String;
public var chatBoxText:String;
// Constructor.
public function CustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false):void
{
super(type, bubbles, cancelable);
}
}
}
Then you can dispatch this with properties defined:
timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
var evt:CustomEvent = new CustomEvent(CustomEvent.SAVE_CHAT);
evt.username = "Marty";
evt.chatBoxText = "Custom events are easy.";
dispatchEvent(evt);
}
And listen for it:
addEventListener(CustomEvent.SAVE_CHAT, saveChat);
function saveChat(e:CustomEvent):void
{
trace(e.username + ": " + e.chatBoxText);
// Output: Marty: Custom events are easy.
}
Actually, you can pass additional parameters to an event listener without creating a custom event by using Actionscript's dynamic function construction.
private function addArguments(method:Function, additionalArguments:Array):Function
{
return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}
When setting up the closeHandler for the Alert window we call the addArguments() method and pass in an array continaing all of the parameters we want to pass to the closeHandler. The addHandler() method will return the function we will call when the Alert window closes with the parameters included.
protected function btnOK_clickHandler(event:MouseEvent):void
{
Alert.show("Would you like to reverse the text you just entered?", "", Alert.YES | Alert.NO, null, addArguments(alertCloseHandler, [txtInput.text]), null, Alert.YES);
txtInput.text = "";
}
1067: Implicit coercion of a value of type void to an unrelated type Function
Pay due attention to the error you got: it says that a Function is a type and that addEventListener() wants it. Although your listener returns void, it is a Function! So, what about returning the listener?
timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));
function saveChat(username:String, chatBoxText:String):Function {
return function(e:TimerEvent):void {
// Do everything that uses "e", "chatBoxText" and "username" here!
};
}
Simple like this. It works for any kind of event. And no closure issues.
Note on removeEventListener():
Don't try to do timer.removeEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText)). It won't recognize your function because you'll be passing a new one on it every time you use saveChat(). Instead, just take its reference out into a variable and you're done:
var functionSaveChat:Function = saveChat(username, chatBoxText);
timer.addEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));
timer.removeEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));
You can try this:
var timerHandler:Function = function (event:TimerEvent):void
{
saveChat(username,chatBoxText,event);
}
timer.addEventListener(TimerEvent.TIMER, timerHandler);
Above calling saveChat(arg, arg, arg) it's not for me, i need to pass arguments that i dont have in this method but i have another solution
Im always using additional method passParameters to adding new arguments:
public function passParameters(method:Function,additionalArguments:Array):Function
{return function(event:Event):void{
method.apply(null, [event].concat(additionalArguments));}
}
explanation of this is here - its simple and always work
http://sinfinity.pl/blog/2012/03/28/adding-parameters-to-event-listener-in-flex-air-as3/
Is there a way to dispatch a SWFAdresss CHANGE Event but also pass parameters (an Object) along with it?
I see something like that in the documentation but I can't find an example online...
You could modify the SWFAddressEvent class like so:
private var _customObject:Object;
public function SWFAddressEvent(type:String, customObject:Object, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
_customObject = customObject;
}
and then when you dispatch the CHANGE event, add the object to the Event:
dispatchEvent(SWFAddressEvent.CHANGE, customObject);
To make the Object publically available:
public function get publicCustomObject():Object
{
return _customObject;
}
I am creating a library. Here is an example
[Event (name="eventAction", type="something")]
public function create_new_customer(phone_number:String):void
{
-------------;
----;
------------;
rpc.addEventListener(Event.COMPLETE, onCreate_returns);
}
private function onCreate_returns(evt:Event):void
{
var ob:Object = evt.target.getResponse();
dispatchEvent(new something("eventAction"));
}
I have a listener to this event in app side. So when I manually dispatch event I want the
"ob" to be sent as a parameter. How to do it?
You need to create a custom event class with extra properties to pass data with it. In your case you could use a class like
public class YourEvent extends Event
{
public static const SOMETHING_HAPPENED: String = "somethingHappend";
public var data: Object;
public function YourEvent(type:String, data: Object, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.data = data;
}
override public function clone():Event
{
return new YourEvent (type, data, bubbles, cancelable);
}
}
then when yo dispatch you do:
dispatchEvent(new YourEvent(YourEvent.SOMETHING_HAPPENED, ob));
In AS3 you can use DataEvent:
ex:
dispatchEvent( new DataEvent(type:String[,bubbles:Boolean=false,cancelable:Boolean=false, data:String ] );
Instead of example data, I showed the parameters DataEvent takes.
I hope this helps.
Best regards, RA.
Make your custom event carry this ob object. Pass it to the custom event's ctor and voila!