How to schedule a removeEventListener inside an addEventListener? - dom-events

I'm trying to define an event listener that can trigger its own removal.
The usual way is to define the listener, then use the reference when calling addEventListener. And using the same reference when calling removeEventListener. As Purescript is a strict language, it seems I can't do that because I can't refer to the listener I'm defining.
import Web.Event.EventTarget
do
listener <- eventListever (\event -> do
somethingUsefulWith event
_ <- removeEventListener evType listener' false target
pure unit
)
addEventListener evType listener false target
I expect listener' to be listener but, as it is impossible, I don't know if there is a simple solution.

The current solution would be to use a Ref.
import Effect.Ref as Ref
example = do
listenerRef <- Ref.new Nothing
listener <- eventListener \event -> do
Ref.read listenerRef >>= traverse_ \listener -> do
removeEventListener evType listener false target
Ref.write (Just listener) listenerRef
addEventListener evType listener false target

Related

How to make a parent movieclip listen to a customevent, dispatched by a child of child movieclip ?

There are 3 Movieclips on stage
A => B => C ( B is the child of A, C is the child of B )
When i use a builtin event like MouseEvent.CLICK, on movieclip "C", then it automatically propogates to movieclip "A". I don't need any type of "dispatch" function at any level. This is understandable, since events propogate from child to parent automatically.
But when i use a customevent say "onMyCustomEvent", and use dispatch function inside "C". I cannot get it propogated ? How can i make the propgation of a customevent, same as how it happens for a built-in event ?
When you register event handler set third parameter useCapture to true.
What you are calling propagation is actually called "bubbling".
An Event bubbles up the display list.
This is also the reason why one should addEventListener() for KeyboardEvent and MouseEvent at the stage in order to capture them regardless of focus:
From wherever the Event starts bubbling up, it will always end up at the stage, which is the top most object in the display list hierarchy.
In order to create a bubbling Event, pass true as the second parameter to the constructor of the Event class:
see here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html#Event%28%29
public function Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
bubbles:Boolean (default = false) — Determines whether the Event object participates in the bubbling stage of the event flow. The default value is false.
You do this when calling super() in your CustomEvent's constructor, e.g.:
super("whatever", true);

as3 - Removing EventListener where function has been defined in addEventListener parameters

If I add event listeners as shown:
buttons[i][j].addEventListener(Event.ENTER_FRAME, function(e:Event){trace("foo");});
How would I go about removing this EventListener?
I've tried this but, it doesn't seem to work. :S
buttons[i][j].removeEventListener(Event.ENTER_FRAME, function(e:Event){trace("foo");});
Thanks in advance!
You can try:
myObject.addEventListener(Event.ENTER_FRAME, function(event:Event):void
{
// event.currentTarget (in this case myObject)
// event.type (in this case Event.ENTER_FRAME)
// arguments.callee (reference to the current function)
event.currentTarget.removeEventListener(event.type, arguments.callee);
trace("foo");
});
It works when you define the function which is called on handling the event.
In your case:
buttons[i][j].addEventListener(Event.ENTER_FRAME, myFunction);
function myFunction(e:Event){
trace("foo");
}
And then to remove the EventListener:
buttons[i][j].removeEventListener(Event.ENTER_FRAME, myFunction);
Hope this helps.
By definition you cannot remove that listener if you define it anonymously. That's the whole purpose of using that syntax. So if you don't mean that then you have to switch to a defined listener. If you do mean that then you have to use weakReference as:
addEventListener(Event.ENTER_FRAME, function(e:Event){trace("foo");}, false, 0, true);
The last parameter 'true' making it weak and making sure the event will be gc when the referenced object will cease to exist.
Using anonymous listener without weakRefernce set to true is an error.

my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, startListener); function startListener (e:Event):void;

can you please help me to find what does e: mean in actionscript 3.0 ?
my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, startListener);
function startListener (e:Event):void;
Event listeners (your function startListener) must receive an Event object. Generally this is written as e:Event but could just as easily be hamSandwich:Event. The important part is that it is an Event object.
e is the Event that was dispatched.
You have an object that's called / referenced by my_loader.contentLoaderInfo. At some point, my_loader.contentLoaderInfo might create an Event object, categorize it as a "complete event" (in other words, Event.COMPLETE), and dispatch it to any functions listening to my_loader.contentLoaderInfo for an Event.COMPLETE event. This is done by calling the functions that are listening for that event.
In this case startListener is one of those functions that's listening for that event on my_loader.contentLoaderInfo, so whenever that kind of event is dispatched from that object, one of the functions that's called is startListener. Notice how the type of object that is dispatched and the type for startListener's lone parameter are the same: Event.
A function that's listening to an object for a type of event may wish to examine the event for certain pieces of information, so when that event is dispatched, it is copied by reference to the listening function as the lone argument. So e is a reference to the event that was created and dispatched.
This next little bit may be jumping ahead, but this is an example of how that might be used: One thing some people like to do is to make the same function listen to multiple objects for the same type of event. Something like:
obj1.addEventListener(Event.COMPLETE, myHandler);
obj2.addEventListener(Event.COMPLETE, myHandler);
obj3.addEventListener(Event.COMPLETE, myHandler);
function myHandler(e:Event):void {
// do some stuff
}
So what if one of those objects dispatches a complete event? How does myHandler know which object it belongs to? By looking at e.target:
function myHandler(e:Event):void {
this.doSomething(e.target);
}
e.target is the actual object that dispatched the event, so if the function is listening to multiple objects for the same type of event, e.target would let the function tell those objects apart.
It's a parameter you passes in your custom function e.g.
//Here, data type is a Number and var name is myNum
function doSquare(myNum:Number):void
{
var mySquare:Number = myNum * myNum;
}
Similarly,
//here type is Event and var name is e (you can have any name like evt, event, myEvt etc)
function startListener (e:Event):void
{
trace(e.target.content.width);
trace(e.target.width);
trace(my_loader.width);
}

AS3: Best way to register event listeners

My question today is about the way we can register an event listener.
Let's say we have a Group element and inside it a custom Handler element. We want the Handler element to do something when Group triggers a custom event. Now, what is the best way to do it?
var group:Group = new Group();
var handler:Handler = new Handler();
group.addElement(handler);
Now, what is the best way to register the event listener?
1. Go on and do it from the file where we initialized the objects
group.addEventListener("CustomEvent", handler.handlerFunction);
2. Register the event listener from the Handler's class:
parent.addEventListener("CustomEvent", handlerFunction);
3. Any other way?
You can let Group class instance dispatch custom event directly on Handler class instance. Handler class would have an internal listener registered for example in constructor.
public function Handler() {
addEventListener("CustomEvent", handlerFunction);
}
Group class would dispatch event following way:
handler.dispatchEvent(new CustomEvent());

Why isn't dispatchEvent firing?

okay so here is my problem in my main project I'm trying to fire an event using dispatchEvent I've made a simple test class to test this and yet it still isn't working...
Here is the test class
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main() {
stage.addEventListener("pOver", rake);
dispatchEvent(new Event("pOver"));
}
public function rake(e:Event):void {
trace("working");
}
}
Why isn't it firing? or why is the listener not capturing that event?
You are dispatching the event on the Main, which is a child of Stage. If you want to specifically dispatch an event on the Stage then use:
stage.dispatchEvent(new Event("pOver"));
Now you may be wondering, "If it's a child, then my event handler should still be getting triggered!"
Well, yes and no.
Lets take a look at a simple diagram of the event life-cycle:
First, the event that you are dispatching is not a bubbling Event. Examining the Event constructor, its signature looks like this:
public function Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
Notice that the second argument is by default false, which means this event does not perform the bubbling part of the event life-cycle.
Second, you have attached the event dispatcher on the bubbling side of the event life-cycle. If you look at the signature for .addEventListener() it looks like this:
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
Notice the third argument. Which is by default false again. This means that you are attaching on the "bubbling" side of the event.
This means that this event is getting to the targeted element, the instance of Main, and then stopping and not going anywhere else.
TL;DR: So what does that all mean?
So to trigger your event handler, and not change where the event gets dispatched, you need to change your event that you are triggering to:
this.dispatchEvent(new Event("pOver", true)); // this event will bubble
Then your event handler, since it is a child, will be triggered by this event.
Conversely, I think that non-bubbling events will also progress through the capturing side of the event life-cycle so you could also change your event listener to attach to that side of the event as well.
stage.addEventListener("pOver", rake, true); // attach to a capturing side
I believe that event will always flow through the capturing phase, even if they are marked as not bubbling. But I could be wrong on that. I just can't remember if "non-bubbling" events skip both capturing and bubbling phases and just trigger the target event phase and I don't have time to check it right now.
Edit
So, I wrote up a quick test on wonderfl:
package {
import flash.events.Event;
import flash.display.Sprite;
public class FlashTest extends Sprite {
private var debug:TextField;
public function FlashTest() {
stage.addEventListener("Foo", bubbleFooHandler);
stage.addEventListener("Foo", captureFooHandler, true);
trace("Ready");
trace("---------------");
trace("Trying a non-bubbling event");
this.dispatchEvent(new Event("Foo"));
trace("---------------");
trace("Trying a bubbling event");
this.dispatchEvent(new Event("Foo", true));
}
private function captureFooHandler(e:Event):void {
trace("Triggered \"Foo\" from capturing phase\n");
}
private function bubbleFooHandler(e:Event):void {
trace("Triggered \"Foo\" from bubbling phase");
}
}
}
The output from this is
Ready
---------------
Trying a non-bubbling event
Triggered "Foo" from capturing phase
---------------
Trying a bubbling event
Triggered "Foo" from capturing phase
Triggered "Foo" from bubbling phase
Notice that events will always progress through the capturing phase. However, if they are not marked as a "bubbling event", see before, they will descent through the tree they stop when they arrive at target of the event (the EventDispatcher the event was dispatched on).
Bubbling events, on the other hand, will turn around and head back up the tree.
Hopefully, this clears things up.
First of all, you are listening to stage events. This means that as long as stage is not dispatching any Events you will not get any callbacks.
try
stage.dispatchEvent(new Event("pOver"));