AS3: How to dispatch function from class to mainframe - actionscript-3

This might be a silly question. But how can I call a function (to execute) from a class to the timeline.
For example, I have the class "Test" and I want to execute the function "Next" on the timline (which it is only a function to show next slide).
Hope you understand what I'm trying to do.
Thank you!

The best practice for communication (in this scenario!) is to use Events.
The timeline create the object of your class Test and registers an
event listener.
The object of your class Test dispatch an Event.
The function that the timeline registered for that Event will be executed.
Please take a look at this question that wants to send additional information to the main timeline. In your case, you do not need a custom Event, because you do not want to send any information along. You only want to communicate the occurrence of the event. You can put that information into the type of the event. an example for a dispatch could look like this:
dispatchEvent(new Event("next"));
Creating a custom class allows you to put that String literal that describes the type into a constant, which prevents errors caused by accidentally misspelling the type. That might be a reason to create a custom Event class anyway, even only for the sake of a place to put those constants.
dispatchEvent(new PresentationEvent(PresentationEvent.NEXT));
Again, this would do the same as the previous line. this is also covered in the other question and the answer to it. Please take a look.

Related

Actionscript: Is passing functions through events a good idea?

I have an event class which extends the normal events class so I can pass parameters and have custom events.
I have a message event which I use to display a message to the user, I send an event to trigger this message from many places in my project.
I now need to give the user an option in this message and access the answer in the original class which sent the event that triggered the message.
My solution is to pass a function as a parameter to the event listener, then on click the function in my original class is called.
Is this a good approach?
My other solution was to create more events to handle the various options, but I may end up with many types of events.
This is not a traditional delegation of concern. If the original class cares about an event, it should listen for it and react to it. If you wanted to extend "event" it would traditionally be to have it carry more data (or more descriptive data), not to have it carry a function closure.

Why use custom events instead of direct method calling?

I'm new to programming and I've been checking a lot of game coding tutorials. I've noticed that on most of them they use custom events to trigger methods instead of calling a method directly.
What's the reasoning behind this practice? Why aren't they just calling the method?
For example:
We have two objects: A and B. A has method A.methodA() that B needs to use when X condition is triggered.
Why implement:
B dispatches an event to A that tells A to run A.methodA()
Instead of:
B uses A.methodA()
The main reason is separation of interests. When using events, class A doesn't need to know about the existence of class B (and vice versa).
Some benefits to this are:
Much easier unit testing (you can test Class A without class B)
Less chance of breaking your code when you change class A or B
Less references to other classes in your code, which reduces the potential for memory leaks
Cleaner code
More flexible/reusable code (a bunch of other classes could all listen/respond to the event without any additional code in the your dispatcher)
Typically in bigger applications using events will help abstract everything. When you have 15+ classes and they're all ditpatching events to a controller, it's a lot easier to figure out what's going on than reading through all different parts of the code to trace functions. Using callbacks begins to create spaghetti code.
However, direct function calls are going to be executed faster than events.
Personally, I use custom events simply for the ease of use. I can have one class dispatch an event when something happens (say an animation finishes or an error occurs in a download) and any number of other classes run any number of other functions based on that event. In addition, I code for reusability. The goal of each class is complete independence so that it can run in any project without needing other packages. So rather than have one class call a method of another class, I dispatch an event from the first class that the second class listens for and then run that method. Then when I need that first class for another project, I can just copy/paste it without having to modify it and without losing any functionality.
EDIT:
Also, it's worth noting that sometimes people do what you describe to get around having to pass in event arguments.
Say you have a button on the stage and you need to be able to click it, but you also need to be able to manually call that method. Some people don't realize you can pass in a null event and have only the single method. Or you can set it as a null default argument, see below:
private function onClickHandler( e:MouseEvent = null ):void{
//as long as you never reference "e" within this method, this method can be used both for MouseEvent listeners and manually calling it elsewhere in the code
}
That technique can help avoid having an event handler that only calls another method and nothing else. At this point in my programming, every single AS3 event handler I write sets the event argument to null by default. It just makes things easier later on.
You might want to read this.
And also note using the callback method allows you to pass parameters to it directly and not via a custom event model.
I built my own, very simplified, events dispatcher system. AS Event model is very powerful, but in 99% of situations you don't need that power. A simple callback with parameters fired as an event is more than enough. You can still retain the versatility from an event model, but don't need to write too many lines of code for, let's say, a simple button.
I can setup a simple event like this:
Buttonizer.autoButton(_buttQuit, this, "onPress");
public function onPressQuit(c:Sprite) {
// Execution goes here
}
You can build your own event model, it will make life simpler, and your code much more concise.

flex 4 - why dispatchEvent triggering creationComplete recursively

I have a custom component called shopView which is an MXML skinnable component. I have a controller class called ShopController which takes care of showing this component in popup, updating info shown in the component etc.
Now, I wanted to maniupate some of the subcomponents of this ShopView after it has been created from the controller after the ShopView is created (creationComplete() event)
So, I have attached an event listener which intern does some initialization process
creationComplete="init(event)"
the init() function
private function init(event:FlexEvent):void{
event.stopImmediatePropagation();
initMenus();
initSlots();
dispatchEvent(event);
}
Attached another creation complete event from the controller class
_shop.addEventListener(FlexEvent.CREATION_COMPLETE,onShopCreated);
*_shop is the instance of ShopView*
Now, if you see the init() function, there I am stopping the event propagation, doing some initialization process and after that I am dispatching the event (for the shop controller do the rest of the job)
Now, this is crashing the app because the crationComplete event of the ShopView is recursively called. I was thinking the dispatchEvent will propagate to the other listerners but seems like it is propagating back to the same component.
I have fixed it by removing the e.stopImmediatePropagation() and dispatchEvent(event) lines from the init() function. But I want to know why it is happening like this?
Is it a known issue for the mxml/flex components? OR it is expected behavior?
Update: I am not doing same in .as as I said below. Got answer, basically its my stupidity :)
because I have not seen this behavior when I write .as classes where I
stopevent propagation and dispatch the event based on business logic.
Thanks in advance.
This is expected behavior.
When you redispatch an existing event dispatchEvent automatically clones it (since you can't dispatch the same event twice.) This clears any propagation-related flags.
May I ask why you want to redispatch CREATION_COMPLETE in this situation anyway? Both handlers will function just fine without the two lines you removed.

How do I attach a global event listener?

I am working on an AIR application:
The main window is like a dashboard. With the menu bar, I can open other windows with dashboard details. When I close these, I'd like to refresh the main window.
I tried to use an event listener, but the result is not good. If I open detail windows directly from the main window, I know how to add an event listener - and it works - but I don't know how to do it, if the detail window is opening from the menubar!
Thanks for helping me.
A Singleton is what you are looking for. Just put an event dispatcher inside and you will be able to listen from everywhere in the application.
A Singleton is like having a unique instance of an object in memory, so anyone modifying a variable inside that object ( or sending events throught ) will be modified for everyone.
Here is an example of code on how to use it.
http://life.neophi.com/danielr/2006/10/singleton_pattern_in_as3.html
Note: Singletons are powerful and dangerous at the same time, there is a lot of talk about how to use them, please read a little more about that if you are considering building a big project.
Hope it helps!
The issue is that you're performing business logic from a View. Don't do this. Instead, dispatch an event from each menu rather than directly opening the window from within it. Listen for those events at a higher level, and then you can either directly listen to the new windows you have opened, or you can create a base window Class that exposes a variable of type IEventDispatcher. If you populate that variable with the same event dispatcher, what you wind up with is called an "event bus," and you can listen on that for events.
This architecture requires a little more thought than using a Singleton, but it avoids the tight coupling and other issues you'll run into by introducing one into your project.
You can listen to an object (EventDispatcher) directly by adding an event listener to it, or if the dispatcher object is on the displaylist, such as a Sprite, you could listen at the stage level with the capture parameter set to true.
But the main caveat is that the dispatcher must be on stage for you to catch this event.
Your main window listens to stage (with capture = true):
stage.addEventListener("MY_CUSTOM_EVENT", handle_custom_event, true);
private function handle_custom_event(e:Event):void
{
var sub_window:Object = e.target;
// do something to your sub_window
}
Your sub window can dispatch events like this:
dispatchEvent(new Event("MY_CUSTOM_EVENT"));
But (ab)using the stage as a message passing infrastructure for custom events in this way is a little messy. You could consider a more formal message passing architecture if you really want this kind of communication. Even a static MessageBus class would at least quickly help you identify where you use this in your codebase. Either way, you'll have to be careful about references and memory leaks.

Problem with event listener added by a weak reference in ActionScript

My problem is basically as follows. There is an instance of a class extending EventDispatcher. Everything goes well when I add event listener to the object like this:
myObject.addEventListener('eventName', someFunction, false, 0, false);
But something changes when event listener is added by a weak reference:
myObject.addEventListener('eventName', someFunction, false, 0, true);
Now someFunction is not called even though the line containing dispatchEvent('eventName') is being executed just like before (and there is an external reference to myObject as well).
The application I’m developing is quite complex so, unfortunately, I can’t post the exact code.
You are misunderstaning how GC works, I think. Using a weak reference will not pin down myObject. It could (possibly, not necessarily) prevent the scope in which the handler is declared to be collected (as long as myObject itself is alive). Hence, the callback itself could be collected, causing it not to be executed. It seems this is the case here, according to your description.
So your goal is to avoid that the scope declaring someFunction is collected. One way could be actually using a hard ref (if you ask me, weak refs are a bad idea, anyway). There may be others, but I don't know how your app is structured, so I can't say much.
Edit to address a comment.
GC wise, event handling is not different from the general case. When you add a listener, you're passing a reference to the dispatcher (the reference is the scope that in which the listener is declared). The dispatches stores this reference so it can execute the callback when neccesary. It's really not that different from this:
myObject.keepThisReference = someFunction;
Now, myObejct has a reference to someFunction. So, as long as myObject is alive, someFunction will be alive too (unless you set someFunction as a weak ref).
So, to answer the question in your comment (an object is not referenced anywhere else but has an event listener attached), given this scenario:
myObject.addEventListener('someEvent',someFunction);
If myObject doesn't have any other reference and goes out of scope, it is collectable.
If there's no other link to myObject, then it'll get collected when the function that you're in goes out of scope. Either change the code so it's not a weak listener, or make sure there's a reference to myObject somewhere else in the code