Not receiving an event fired from an .AS class - apache-flex

I have 2 files, 1 to dispatch the event and 1 to receive it (of course in addition to the event class itself).
I've done this before with both dispatching and receiving files being mxml, but this time the dispatching file is an actionscript class, and it's not working this time. Is it different for actionscript classes?
Here's a dumbed down version
The dispatching class dispatches the event as soon as it's created.
public class ASClass extends UIComponent{
public function ASClass(){
dispatchEvent(new MyEvents(MyEvents.FIRE_EVENT));
}
}
in my main mxml app, I instantiate the ASClass which automatically dispatch the event as soon as it's created and the main mxml app should receive back. But something's not working.
protected function appCComplete(event:FlexEvent):void{
addEventListener(MyEvents.FIRE_EVENT, gotEvent);
var asClass:ASClass = new ASClass();
}
protected function gotEvent(event:MyEvents):void{
Alert.show("got event");
}

addEventListener(MyEvents.FIRE_EVENT, gotEvent);
is same as
this.addEventListener(MyEvents.FIRE_EVENT, gotEvent);
which listens for FIRE_EVENT dispatched by this object - your main mxml app. To listen for events fired from asClass object, you have to call addEventListener on that object.
asClass.addEventListener(MyEvents.FIRE_EVENT, gotEvent);
Thus, you cannot listen for events fired from the constructor. The following code shows the correct way to listen to the events fired by the asClass object (from anywhere but the constructor).
protected function appCComplete(event:FlexEvent):void{
var asClass:ASClass = new ASClass();
asClass.addEventListener(MyEvents.FIRE_EVENT, gotEvent);
}
protected function gotEvent(event:MyEvents):void{
Alert.show("got event");
}
If you think about it, you can see that it makes sense. The constructor is used to create an object - event subscribers are normally interested in some actions/changes occurring to the object once the object is fully built and functional.
That said, you can pass a reference to this or the function to the constructor of ASClass and then assign that function as the event listener from within the constructor if you want.
public class ASClass extends UIComponent{
public function ASClass(listener:Function){
this.addEventListener(MyEvents.FIRE_EVENT, listener);
dispatchEvent(new MyEvents(MyEvents.FIRE_EVENT));
}
}
var asClass:ASClass = new ASClass(this.gotEvent);//pass the function.
//or
public class ASClass extends UIComponent{
public function ASClass(listenerObj:Object){
this.addEventListener(MyEvents.FIRE_EVENT, listenerObj.gotEvent);
dispatchEvent(new MyEvents(MyEvents.FIRE_EVENT));
}
}
var asClass:ASClass = new ASClass(this);//pass the object.
Personally, I can't think of many scenarios where I'd want to go this way: consider some redesigning so that you listen to the events after the constructor returns.

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;

Flex 4 - Problem listening to an event in Main.mxml from a UIComponent extended custom class

I've run into weird issue.I've a main game class which extends UIComponent and basecly glue all game logic together - main loop.Then I've app main.mxml file which initialize main game class,keep care of game screen state(main menu,game,game over,etc..) and add some ui control - flex is great for that.Nonetheless problem arrive when I'm trying listen on custom event in Main.mxml which is dispatched in Game class.
**GameStateEvent.as**
public class GameStateEvent extends Event
{
public static const GAME_OVER:String = "gameOver";
public static const NEW_LEVEL:String = "newLevel";
public function GameStateEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
override public function clone():Event
{
return new GameStateEvent(type, bubbles, cancelable);
}
}
Game.as
[Event(name="gameOver", type="custom.events.GameStateEvent")]
public class Game extends UIComponent
private function checkforEndGame():void
{
if(_gameOver == true)
{
dispatchEvent(new GameStateEvent(GameStateEvent.GAME_OVER)); //true
}
}
Main.mxml
<fx:Script>
<![CDATA[
protected function game_gameOverHandler(event:GameStateEvent):void
{
//This event never got dispatched
}
]]>
</fx:Script>
<game:Game id="game" includeIn="GameState" gameOver="game_gameOverHandler(event)"/>
I'm really stack in this - things seems simple but for reasons I unknown nothing seems to work.I tried capturing,bubbling event - nothing, event never got dispatched in Main.mxml.
Problem is solved.Actually I little bit lied about when dispatchEvent because for test purpose I dispatchEvent append constructor initialize process.Ok, my bad I'm more experienced and comfortable with pure actionscript - but is it true that I can't listen on event in app Main.mxml from component while it constructor initialize process is done?Because after that everything works smoothly.

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.

Flex Listening for Events Issue

I am rather new to flex and am trying to figure out how to listen for a custom event I have created. Let me give you a little background on my app first.
My directory structure is as follows.
assets
components
control
events
model
util
In the model class (which is bindable) I have an ArrayCollection which will get loaded with data via a web service call and a datagrid in a specific component will bind to that ArrayCollection and display the data. The web service is invoked via a button press which initiates the search through an event.
model/ApplicationModel.as
[Bindable]
public class ApplicationModel
{
//put specific model components here
public var data:ArrayCollection;
//the one instance in this Singleton
private static var _instance:ApplicationModel;
public function ApplicationModel()
{
if (_instance != null) throw new Error("ApplicationModel already exists!");
}
public static function getInstance():ApplicationModel
{
if (_instance == null) _instance = new ApplicationModel();
return _instance;
}
}
components/SearchBox.mxml
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import com.homedepot.di.tp.SCVTools.events.*;
private function doSearch():void
{
var query:String = searchTI.text;
//only want to dispatch an event if there is something to query
if (query) dispatchEvent(new CustomEvent(CustomEvent.UPDATE_START,query));
}
]]>
</mx:Script>
<mx:Label text="Enter Search Term"/>
<mx:TextInput id="searchTI" enter="doSearch()" />
<mx:Button label="Search" click="doSearch()"/>
</mx:HBox>
This search functionality works fine and will return the data that I want. What I need to be able to know is when this web service call is done so the view component can update other aspects of the view accordingly (hide columns of datagrid based on the data returned as an example).
My Application.mxml file will wire up my controller to listen for the CustomEvent. The controller will then delegate the work to actually call the web service and get the data. The delegate will create an HTTPService object and get the data. It will also process results of the HTTPService. I am currently trying to dispatch a new event in the function that handles the result of the HTTPService call. This does not seem to be working and it makes sense since the event will never bubble to my view component.
snippet of control/DataUpdateDelegate.as
public override function parse(event:ResultEvent):void
{
super.parse(event);
try
{
Application.debug("DataUpdateDelegate:parse");
var data:Object = event.result.records.record;
model.data = data as ArrayCollection;
dispatchEvent(new CustomEvent(CustomEevent.UPDATE_END) );
}
catch (error:Error)
{
handleError(error);
}
}
I have tried to wire this UPDATE_END event up in the Application.mxml file but that does not seem to work either.
Does anyone have any suggestions on how my view to listen to this event that is not dispatched from a child component but rather from an ActionScript class that knows nothing about the view component?
Thanks,
Thomas
You could bind a specific function to the data property using BindingUtils when your ApplicationModel is first set in your view:
public function set model(applicationModelInstance:ApplicationModel):void
{
_applcationModelInstance = applicationModelInstance;
BindingUtils.bindSetter(dataRefreshed, _applicationModelInstance, "data");
}
protected function dataRefreshed(value:Object):void
{
// do whatever you need to do here.
// value==applicationModelInstance.data
}
De-registering a binding like this to avoid memory leaks is a bit tricky, but since your ApplicationModel is a singleton you don't need to anyways.

move data from progress event to another class

in Flex if i have a loader class (i.e., XMLLoader) and a document class (document.as) and in document.as I'm instantiating XMLLoader
var ldr:XMLLoader = new XMLLoader(url);
... and on the document.as class I have a text box, which I would like updated with the progress from that XMLLoader is making by using URLLoaders progress event, continously. Meaning, the box would show the load in bytes that it is recieving
I'm not sure how to constantly push data out of an event and add it to another class. For example:
myLstnr.addEventListener(ProgressEvent.PROGRESS, getProgress);
private function getProgress():void
{
// as progress updates, move it to document.as class's textbox
{
You will want to re-dispatch the ProgressEvent. You can use a custom made event to store your event object. So for example:
private function getProgress(event:ProgressEvent):void {
dispatchEvent(new CustomObjectDataEvent(event, 'progress'));
}
Where CustomObjectDataEvent is a custom event class that you create that stores an object(the ProgressEvent) in your custom event object. Here is an example implementation of the custom event that stores this object:
package events
{
import flash.events.Event;
public class CustomObjectDataEvent extends Event
{
public var objectData:Object;
public function CustomObjectDataEvent(objectData:Object, type:String, bubbles:Boolean=false) {
super(type, bubbles);
this.objectData = objectData;
}
public override function clone():Event {
return new CustomObjectDataEvent(objectData, type, bubbles);
}
}
}
Check out: http://livedocs.adobe.com/flex/3/html/createevents_3.html for more information on dispatching custom events.
Your event handler (getProcess) must accept the ProgressEvent as a parameter. From that, you get the needed info. When you do, just write it out to the text field you want, e.g.
document.textfield.text = event.bytesLoaded;
You can dispatch an event to the other class from inside your getProgress(). Creating custom events

Resources