I want to create a custom event and it will be accessible by any other class.
Suppose I have NavigationMenuClass.as which contains some next, prev buttons, and another class For Page.as which should show a particular page at each next or prev button press.
And I need to create a custom event(will write a EVENTClass.as to manage all these kind of events.) called "showPage", and when this event occures the Page.as class member function need be called.
private function nextPress(event:Event) {
//dispatchEvent(new Event("showPage"));
// this will call the Page class Menmber function page:Page = new Page; page.showNextPage();
}
With out passing the object how can I call a particular member function using Event and Event Dispatcher methods.
You seem kind of confused.
So, you have a display hierarchy in which your Page.as display object is the parent of the NavigationMenuClass.as, correct?
Your NavigationMenuClass should dispatch events for 'next' and 'previous'. The Page class should listen to those events and do something.
Your code kind of already does the dispatching part, although it is commented out. I would put this in the click handler of your button and use it to dispatch a next, or previous, event:
private function nextPress(event:Event) {
// dispatchEvent(new Event("showPage"));
// this will call the Page class Menmber function page:Page = new Page; page.showNextPage();
dispatchEvent(new Event("next"));
}
In your Page.as you just add an event listener:
navigationMenuClassInstance.addEventListener('next', onNext);
public function onNext(event:Event):void{
// write code to change content
}
You can use the same approach to implement the previous event. To address a few of your "odd wordings"
I want to create a custom event and it
will be accessible by any other class
I'm not sure what you mean by accessible.
You can create a custom event class that extends Event and any other class can use it, as long as it imports it. My example above doesn't create a custom event class, but uses the default event class.
In terms of dispatching, the event only dispatches itself up to its' parent. IF the event bubbles, it will go to it's parent parent, then the parent's parent, and so on all the way up the the stage.
With out passing the object how can I
call a particular member function
using Event and Event Dispatcher
methods.
I'm not sure what you mean by "passing the object" here. When you dispatch an event, that event class is always available to the event listener as an argument to that event listener method. That is kind of like passing an object.
Also when following Flextras excellent guide, make sure that NavigationMenuClass extends EventDispatcher, otherwise just calling the dispatchEvent() method won't work!
Related
I hava a custom component and it contains a child icon. If I add a mouse-click event listener to both component(click-listener1) and icon(click-listener2), the event dispatched sequence is click-listener2, then click-listener1. I can understand it. But if I add a custom event to component (listener1), and mouse-click event to icon(listener2), when icon is clicked, the component will dispatch the custom event. In my test, the event dispatched sequence is listener1, then listener2. It doesn't match with event-bubbles rule.
In my opinion The custom event is dispatched in listener2, which triggers listener1. Why event flow sequence is not listener2, listener1?
In component.
icon.addEventListener(MouseEvent.CLICK, iconClickHandler);
private function iconClickHandler(event:MouseEvent):void
{
trace ("Listener2");
var customEvent:CustomEvent= new CustomEvent(CustomEvent.CUSTOM_EVENT, true, true);
dispatchEvent(customEvent)
trace ("Listener3");
}
In Application, which contains component
component.addEventListener(CustomEvent.CUSTOM_EVENT, customEventHandler);
private function customEventHandler(event:CustomEvent):void {
trace ("Listener1");
}
UPD
You've got:
private function iconClickHandler(event:MouseEvent):void
{
trace("listener2");
var customEvent:CustomEvent= new CustomEvent(CustomEvent.CUSTOM_EVENT, true, true);
dispatchEvent(customEvent);
trace("listener3");
}
private function customEventHandler(event:CustomEvent):void
{
trace("listener1");
}
When MouseEvent.MOUSE_CLICK is dispatched, it triggers first lucky listener - it is your component function iconClickHandler. Here we trace "listener2" and dispatch custom event.
Due to syncronious nature of events, CUSTOM_EVENT listeners are triggered immediatly, that means that dispatching an event is similar to calling listener functions. Events are not stored anywhere, they are not delayed: listeners to events fires immediatly, in the same control flow, in the same thread.
CUSTOM_EVENT was dispatched, its listeners were triggered - we've got a call to customEventHandler and "listener1" in console.
When all the listeners were triggered, control returns to iconClickHandler and "listener3" is traced to console.
That's why we've got output:
listener2
listener1
listener3
I have a child component that dispatches an event in Parent. The event in parent makes a call to our database. Right now, the event gets fired off & the child continues without the results. How do I make it so that the child waits for the results from the database b/f the child continues?
in child:
<fx:Script>
<![CDATA[
dispatchEvent(new Event("getDBcontents")); // dispatch the event in the parent
// do some more stuff here but we need pause until we get the result from the parent
]]>
</fx:Script>
in parent:
public function getDBcontents(event:Event):void {
otherChild.getResult.token = otherChild.childRet.getContents( 'userID.text' );
}
Move the "// do some more stuff here but we need pause until we get the result from the parent" section to a different part. I assume that you are doing a remote call to your database that that has a callback. I'm not sure which mechanism you're using, but let's assume a RemoteObject.
You can pass a function on a custom event that you dispatch. The database section of your code can attach that function pointer to the AsyncToken or just add it to the class instance. Then when it comes back with results you can then call the function that you had passed in as part of the event. The joys of async programming.
I'd recommend looking at the patterns used in Cairngorm and Swiz (Swiz being my preferred framework) as the way they do database calls in those frameworks is exactly what you're trying to do here.
As an example, you could do something like this:
dispatchEvent(new MyCustomEvent("getDBcontents", callBackFunction));
private function callBackFunction(stuffToProcess:Object):void {
//do more stuff here after the stuff is returned
}
//first create MyCustomEvent class extending Event
//Then you need something to handle the event, you can build the event listener yourself, or use something like Swiz to make your life easier
//here is your event handler that you can call yourself, or assign through Swiz Cairngorm
var st:Function;
public myEventHandler(event:MyCustomEvent):void {
st = event.callBackFunction; //your param on your custom function
var token:AsyncToken=this.service.doSomething();
var responder:mx.rpc.Responder=new mx.rpc.Responder(genericResultsHandler, faultHandler);
token.addResponder(responder);
}
genericResultsHandler(result:ResultEvent):void{
if (st != null)
st(result.data);
}
In Flex, is it possible to listen to all event types of an object that's an IEventDispatcher? addEventListener's first parameter is the type, which is a string. In many cases the documentation is not clear what event type it fires. I'd like to attach a generic listener to inspect the events.
I think you have to derive from this class and override the dispatchEvent method like this:
override public function dispatchEvent(event:Event):Boolean
{
trace(event.type);
return super.dispatchEvent(event);
}
The short answer is no, there isn't any built-in way of generically listening for all event types. You would either have to develop a system for managing this or do something similar to what splash suggested. Personally, I would create a custom event, override dispatchEvent, and dispatch your own custom event while passing the 'type' of the original event.
override public function dispatchEvent(event:Event):Boolean
{
//Dispatch your custom event passing along with it the type of the original event.
super.dispatchEvent(new CustomEvent(CustomEvent.ALL, event.type);
return super.dispatchEvent(event);
}
Then you could simply setup one listener for your custom event and easily track when and what events are firing.
Hope that helps.
I have a flex app with lots of nested views and popup windows..
I'd love to catch all the CHANGE events in the application at the top level.. all of them, simply to notify the user that he has changed something (trust me it makes sense in my app).
Now, I tried to add an event listener in the Application creationComplete handler like this:
private function init():void {
this.addEventListener(flash.events.Event.CHANGE, function f():void {...})
}
but it does not work.. why? I read in the docs that event bubbling for the CHANGE event is set to false before dispatching. How can I change that? Is there any other way to achieve my goal?
thanks
Try listening to events on the SystemManager instead of the Application. As far as I understand, SystemManager sits at the very top of the display list, adding the application, popups and other UI entities as children.
In Flex 3 and below, you can retrieve it via Application.application.systemManager.
Read more on the SystemManager on Deepa's blog:
http://iamdeepa.com/blog/?p=11
I am also having trouble with a group of TextArea controls where I would like to listen for the change event on their container (parent) instead.
What I did in the end was to extend the TextArea class and create a listener for the change event. From the listener I would then dispatch a custom event that could bubble.
public class BubblingTextArea extends TextArea
{
public function BubblingTextArea()
{
super();
addEventListener(TextOperationEvent.CHANGE, changeHandler);
}
private function changeHandler(event:TextOperationEvent):void
{
dispatchEvent(new ChangeBubbleEvent(ChangeBubbleEvent.BUBBLE_CHANGE));
}
}
The custom event:
public class ChangeBubbleEvent extends Event
{
public static const BUBBLE_CHANGE:String = "bubbleChange";
public function ChangeBubbleEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
I am sure someone can come up with a more elegant solution since I am still quite new to Flex and AS3 myself.
As far as I know, PopUps happen outside of the Application's main displayList, so that's probably why you're not seeing bubbling. In this case, you'll need to manually add listeners to popups. The Flash change event does bubble according to the docs: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html#CHANGE
I personally like to use a framework such as RobotLegs or Parsley.
The basic idea is that each view and popup gets a mediator. The mediator's job is to communicate between the view and the command/model. Those mediators can listen directly to the view and the view's components.
I've got a class that extends EventDispatcher.
What I want to do is to dispatch the click event when the component is clicked. (The class is essentially some text in a textfield that needs to be able to do certain things, and it needs to be able to respond to a click). Sounds easy enough... I want the event dispatched when that portion of the text is clicked. But uh...how? it's not like a button where I can just go
myButton.addEventListener(MouseEvent.CLICK, myClickHandler);
That's clear, because some component is going to be listening for the Click event dispatched when myButton is clicked. It is built into the AS3 framework that a button knows how to listen for a click event.
After the import statements I've got:
[Event(name="click" type="mx.events.Event")]
How do I dispatch the event when the component is clicked, when the component doesn't yet know how to respond to a click event? I've tried adding an event listener in the textfield which contains this custom class of text, but nothing's happening because the Click event hasn't been dispatched.
You can create your own click event and dispatch it. You can do that also to dispatch clicks on objects where no user ever have clicked :D
Try this:
var mEvent:MouseEvent = new MouseEvent(MouseEvent.CLICK, [HERE MORE PARAMS BY YOU]);
yourObject.dispatchEvent(mEvent);
Now, you will recieve Click Events from yourObject.
Let's say your class consists TextField tf. Then public function YourClass():void { //Constructor
{
//intialize Something
//initialize tf
tf.addEventListener(MouseEvent.CLICK, onClick);
...
}
...
private function onClick(e:MouseEvent):void {
this.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
OK, I tried this in the constructor:
var mEvent:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false);
this.dispatchEvent(mEvent);
Then, in the containing textfield, while iterating through these objects (each of which is called cp), I did this:
cp.addEventListener(MouseEvent.CLICK, mouseClickHandler);
Finally the mouseClickHandler:
private function mouseClickHandler(event:MouseEvent):void
{
trace("Clicked!!!!!!!!!!!");
}
Running in debug mode I get nada. Nunca. Niente. Nuttin'. Which is to say: no trace of being clicked. Did I do something wrong?