Dispatching events from a ActionScript class - apache-flex

package com.services
{
import com.asfusion.mate.events.ResponseEvent;
import com.events.navigation.DesgManagementEvent
import flash.events.EventDispatcher;
import mx.controls.Alert;
public class UserManager extends EventDispatcher
{
[Bindable]
public var addResult:String
[Bindable]
public var user:User
public function UserManager()
{
}
public function addUsersResult(Result:String):void {
addResult = Result
//Alert.show(event.result.toString());
Alert.show(addResult);
backHome();
}
private function addUsersFault(event:ResponseEvent):void {
Alert.show(event.faultString, "Error Executing Call");
}
private function backHome():void {
this.dispatchEvent(new DesgManagementEvent(DesgManagementEvent.DES_HOME));
}
}
}
I am able to get the result, but not able to dispatch the event from the custom actionScript class. I googled and got the riposte that you need to add it to display list.
Can anyone figure out where i am going wrong. The method backHome is not being called at all.

I believe you are expecting to get DesgManagementEvent in the event map and because you don't see it being handled, you believe that bakcHome is not being called.
As you said, events dispatched from an object component that is not in the display list will never reach the event map. You need to pass the dispatcher and use that to dispatch the event. You can pass it in the constructor (first objectBuilder) or as a property (second objectBuilder).
<EventHandlers type="{FlexEvent.INITIALIZE}">
<ObjectBuilder generator="{MyManager}" constructorArguments="{scope.dispatcher}"/>
<ObjectBuilder generator="{MyManager2}">
<Properties dispatcher="{scope.dispatcher}"/>
</ObjectBuilder>
</EventHandlers>
If you use the constructor, then it will look something like this:
public function MyManager(dispatcher:IEventDispatcher)
{
this.dispatcher = dispatcher;
}
Then you will use your dispatcher property to dispatch the event:
dispatcher.dispatchEvent(new DesgManagementEvent(DesgManagementEvent.DES_HOME));

Are you sure you're receiving type String when addUsersResult() is called?

Related

Listen to custom event in flex

I created a custom event with a custom property in actionscript. I can dispatch a custom event (in Main.mxml) with a custom property but I'm not able to listen for this event anywhere else in my application. I'm trying to listen to this event in a custom component.
When I debug I can confirm that the event gets dispatched correctly with the right value.
Snippet of Main.mxml:
var userid:String = result.charAt(4);
//dispatch a custom event in which we store the userid
var event_userid:MyEvent = new MyEvent(MyEvent.COMPLETE,userid);
dispatchEvent(event_userid);
CustomEvent class:
package ownASClass
{
{
//http://stackoverflow.com/questions/1729470/attaching-a-property-to-an-event-in-flex-as3
import flash.events.Event;
public class MyEvent extends Event
{
public static const COMPLETE:String = "MyEventComplete";
public var myCustomProperty:*;
public function MyEvent(type:String, prop:*) :void
{
super(type,true);
myCustomProperty = prop;
}
//override clone() so your event bubbles correctly
override public function clone() :Event {
return new MyEvent(this.type, this.myCustomProperty)
}
}
}
}
I listen to this event in my custom component:
//init gets called as: initialize="init();
protected function init():void
{
//add evt listener for custom event to get userid
this.parentApplication.addEventListener(MyEvent.COMPLETE,getUserid);
//my custom component is part of a viewstack defined in main.mxml
}
protected function getUserid(event:Event):void
{
//do something (but this never gets called)
}
protected function init():void
{
//add evt listener for custom event to get userid
this.parentApplication.addEventListener(MyEvent.COMPLETE,getUserid);
//my custom component is part of a viewstack defined in main.mxml
}
Please try to change above line as follows -
this.addEventListener(MyEvent.COMPLETE,getUserid);
Events typically 'bubble up' the chain from child windows to parent to application(main.mxml).
http://livedocs.adobe.com/flex/3/html/help.html?content=events_08.html
If you are trying to use an event to signal some sub-object you'll need to target it there and have a registered event listener.
Used a workaround for this, realized I didn't really need to dispatch a custom event.
Declared my userid in main application and called it in my component with:
public var userid:String = FlexGlobals.topLevelApplication.userid;

Itemrenderer Dispatch Custom Event

I'm trying to dispatch a custom event from a custom ItemRenderer
This is my custom event
package events
{
import customClass.Product;
import flash.events.Event;
public class CopyProductEvent extends Event
{
public static const COPY_PRODUCT:String = "COPY_PRODUCT";
public var picked:Prodotti;
public function CopyProductEvent(type:String, picked:Product)
{
super(type);
this.picked = picked;
}
}
}
In the itemRenderer I have a function that does that:
private function sendEvent(o:Product):void
{
dispatchEvent(new CopyProductEvent(CopyProductEvent.COPY_PRODUCT,o));
}
And in the main application I have a spark List and I tried to add an EventListener both to the application and the list itself, but they never be called...
this.addEventListener(CopyProductEvent.COPY_PRODUCT,
function(e:Product):void{
...
});
list.addEventListener(CopyProductEvent.COPY_PRODUCT,
function(e:Product):void{
...
});
Why?!? Where am I doing wrong?
The event from the function is dispatched correctly... I can't intercept it..
Sounds like your event isn't bubbling.
Add the bubbles argument (which by default, is false) in your Custom event constructor:
public function CopyProductEvent(type:String, picked:Product, bubbles:Boolean = true)
{
super(type,bubbles);
this.picked = picked;
}
A nice explanation on Event bubbling in AS3 can be found here:
Event Bubbling in AS3

How do I addEventListener to custom actionscript class?

I have an actionscript class MyClass that extens NavigatorContent. I instantiate the class as a custom MXML NavigatorContnent component for an Accordion component. MyClass has a Button component that I have tried to attach an event listener to. I want the event to bubble so that I can have the handler in the Accordion component.
MyClass
package comp
{
import flash.events.Event;
import flash.events.MouseEvent;
[Event(name="selectEvent", type="flash.events.Event")]
public class MyClass extends NavigatorContent
{
public function MyClass()
{
super();
btnSelect.addEventListener(MouseEvent.CLICK, selectClickDispatcher);
}
public function selectClickDispatcher(event:MouseEvent):void
{
event.currentTarget.dispatchEvent(new Event("selectEvent",true));
}
}
}
From here I have the instantiated component nested in the Accordion. I am pretty sure the problem is in this class definition because when I set a breakpoint at the selectClickHandler, the code does not break. In case I am wrong I will post the rest of the components.
Custom component named MySubComp.mxml
<comp:MyClass
...I have a few more spark components here and nothing else...
/>
Accordion
<mx:Accordion>
<fx:Script> //omitted CDATA tags to save space
protected function selectEventHandler(event:Event):void
{
Alert.show("Value Selected");
}
</fx:Script>
//custom components are in the navs package
<navs:MySubComp selectEvent = "selectEventHandler(event)"/>
</mx:Accordion>
You have added the metadata to the class definition
[Event(name="selectEvent", type="flash.events.Event")]
so all you need to do in mxml is
<comp:MyClass selectEvent="event_handler(event)"
..... />
In AS3, you add an event listener by
myClass.addEventListener("selectEvent", event_handler);
P.S. Your class will have to extend EventDispatcher
Your class either needs to extend a DisplayObject class, or directly inherit from EventDispatcher in order to be able to use events. Forget about implementing IEventDispatcher as there's a special piece of black code somewhere that means that EventDispatcher is the only class that can set the target property of the Event class (I've tried it before).
Consider using other alternatives. Events in Flash tend to be slow and create objects all the time. Callbacks are a good system if you need something simple.
public class A
{
public var onSomething:Function = null;
public function foo():void
{
if( this.onSomething != null )
this.onSomething();
}
}
public class B
{
public function B()
{
var a:A = new A;
a.onSomething = this._somethingCalled; // set the callback
a.init();
}
private function _somethingCalled():void
{
trace( "hello there" );
}
}
You can also take a look at the Signals project: https://github.com/robertpenner/as3-signals/wiki
Signals are vastly superior to normal Flash events, and there's no restriction on the type of object that can use them (i.e. non-DisplayObject objects can still add event listeners and dispatch events). It's also faster and has a smaller memory footprint.
In case someone needs the real Actionscript-3 event dispatching to be used >>> this <<< is very helpful. I don't know if it is really slow but it meets the AS-3 standards.

Flex/Actionscript : passing data from custom class to main application?

Ok this probably sounds dumb but Im a complete beginner in Flex programming.
I have an application with a main .mxml file, and a certain class Foo that I call from the .mxml
In Foo, I make a URLRequest and listen for the Complete event. Then I found myself with the returned data in a Foo function, but I have no idea how to communicate it to the .mxml part of the applicaton ! I looked into ArrayCollections but I can't seem to understand how they work and whether it might help. Isn't there a way to modify, from inside the class, a variable with a global scope ?
This sounds like a small application, but if it's a large application you might want to look at a micro-framework like RobotLegs
If you have your Foo class extend EventDispatcher then it will be able to send events and have the main MXML app listen for said events.
package com.example
{
import flash.events.EventDispatcher;
import com.example.events.MyEvent;
public class Foo extends EventDispatcher
{
public function doAction():void
{
var someData:String = "blah";
dispatchEvent(new MyEvent(MyEvent.SOMETHING_HAPPENED, someData));
}
}
}
A Custom event with a payload (in this case a string)
package com.example.events
{
import flash.events.Event;
public class MyEvent extends Event
{
static public const SOMETHING_HAPPENED:String = "somethingHappened";
private var _myData:String;
public function get myData():String
{
return _myData;
}
public function MyEvent(type:String, myData:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
_myData = myData;
super(type, bubbles, cancelable);
}
override public function clone():Event
{
return new MyEvent(type, myData, bubbles, cancelable);
}
}
}
Working with your Foo class from the main file:
public function EventDispatcherExample() {
var foo:Foo = new Foo();
foo.addEventListener(MyEvent.SOMETHING_HAPPENED, actionHandler);
foo.doAction();
}
private function actionHandler(e:MyEvent):void {
trace("my data is: " + e.myData);
}
import mx.core.FlexGlobals;
FlexGlobals.toplevelApplication.varName;
Your Foo class can dispatch an event and have something in you main.mxml listen for that event. I am sure that I could create an example. I think it is under customer events in Flex documentation. This is assuming I understand the question.
As John said, an event is your best choice.
If you'd like some example code, I provided some for a similar question here: Data from Popup to Main Application?
An event might be the best way to do it as it has been stated.
Another approach is to dispatch an event like this
dispatchEvent(new Event('somethingHappened'));
and also create a get method in your class for the data you need to get.
Then all you have to do in your main app is this
var foo:Foo = new Foo();
foo.addEventListener('somethingHappened', actionHandler);
private function actionHandler(e:Event):void
{
trace(foo.memberData);
}
This way might be more suitable if the data should be a class member anyway and if you would like to avoid creating a new event class.

Flex event will only fire once

In an AIR application, I have a private variable and a setter:
private var _saveResult
public function set saveResult( result:String ):void
{
_saveResult = result;
dispatchEvent( new resultUpdatedEvent( _saveResult ));
}
The first time that I set "saveResult" the event fires. But it will never fire again unless I restart the application.
If I change the setter to:
public function set saveResult( result:String ):void
{
_saveResult = result;
if ( result != null)
{
dispatchEvent( new resultUpdatedEvent( _saveResult ));
}
}
The problem goes away, I can set the variable many times and the event fires every time.
My question:
Am I doing something wrong here? If not, can anyone explain to me whats happening? If so, what SHOULD I be doing?
Thanks!
It looks like you're constructing your event incorrectly. The first parameter of an Event object should always be a string. So in this case you'd want to always use the same string so you could listen for the event. What does your resultUpdatedEvent class look like? You'll want it to look something like this:
package myEvents
{
import flash.events.Event;
public class PropertyChangeEvent extends Event
{
public static const PROPERTY_CHANGE:String = "propertyChange";
public var result:String = "";
// Public constructor.
public function PropertyChangeEvent (type:String,
result:String="") {
// Call the constructor of the superclass.
super(type);
// Set the new property.
this.result= result;
}
// Override the inherited clone() method.
override public function clone():Event {
return new PropertyChangeEvent(type, result);
}
}
}
That way, when you go to dispatch your event, you can construct the event as follows:
new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, result);
That way, you're listening for the event "PropertyChangeEvent.PROPERTY_CHANGE", which never changes. The problem is now your event listener is probably listening for an event represented by the string saved in result, and obviously, this changes after the first time it's set, so there's no way to assign a listener to it.
For more information about how events work in AS3: http://livedocs.adobe.com/flex/3/html/help.html?content=events_02.html
Per the comments...
There was no event dispatcher problem.
I misdiagnosed the problem, the REAL problem was that if you have a [Bindable] property and you use a setter, and you set it for the current value, flex will ignore it. SO, you have several choices:
1) give the getter and setter different names. Seems like a "bad idea" but it does fix the problem.
2) remove [Bindable] from either the class (my problem) or the property. If the class does not implement IEventDispatcher, you will need to do so. You can simply "extends Sprite" to see it work, but that seems like a "bad idea" as a solution, so I implemented IEventDispatcher per the example at the end of this page: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/IEventDispatcher.html
3) I am sure that there is a way to get around this bug, but I don't actually NEED the class to be [Bindable] so I did not find a work around.

Resources