Unable to dispatch custom event in flex mobile application - apache-flex

I am trying to get some code working from an example I came across. most of the functionality works but it is failing when it tries to dispatch a custom event. At the moment the code that is trying to dispatch the event is inside a class that handles amf remoting.
the example has this line in it for the dispatch:
Application.application.dispatchEvent(new
RemoteResultEvent(RemoteResultEvent.USER_UPDATE_COMPLETE,"test"));
but that fails as it does not know what application.application is "Multiple markers at this line:
-Access of undefined property application"
I assume that this is because this was not written for a mobile app. I tried changing the dispatcher to EventDispatcher
EventDispatcher(
new RemoteResultEvent(RemoteResultEvent.USER_UPDATE_COMPLETE, "worked"));
but I then get this error:
TypeError: Error #1034: Type Coercion failed: cannot convert events::RemoteResultEvent#18337731 to flash.events.EventDispatcher.
This is the code in the custom event RemoteResultEvent.as :
package events
{
import flash.events.Event;
public class RemoteResultEvent extends Event {
public static var USER_UPDATE_COMPLETE:String = "UserUpdateComplete";
public var message:String;
public function RemoteResultEvent(eventType:String, message:String) {
super(eventType, false, false);
this.message = message;
}
}
}
I am bumbling around in the dark as I am new to flex and this type of development so I could well be doing something really dumb. Any help would be gratefully received.
Thanks
JaChNo

You seem confused about event dispatching in general.
Events can be dispatched in any Flex class that extends, or has a, EventDispatcher. Most Flex Components, including Application extend EventDispatcher. To dispatch the event, you are on the right track just do:
dispatchEvent(new RemoteResultEvent(RemoteResultEvent.USER_UPDATE_COMPLETE,"test"));
That will dispatch the event from your current class. Not that all Flex UI Components, including those made in MXML can be considered a class.
What you are trying to do is dispatch the event on the main level application; which is a horrible encapsulation breach, but doable. You have to cast it as an Application so you do not get a generic object. Like this:
(Application.application as Application).dispatchEvent(new RemoteResultEvent(RemoteResultEvent.USER_UPDATE_COMPLETE,"test"));
This approach is deprecated since Flex 4; and you use the FlexGlobals.topLevelApplication instead:
(FlexGlobals.topLevelapplication as Application).dispatchEvent(new RemoteResultEvent(RemoteResultEvent.USER_UPDATE_COMPLETE,"test"))
You don't say, but you allude to the fact that you are in a Mobile Project. If so, I would not expect the mx Application class to be available unless you explicitly added the SWC w/ MX Components to your class. You'll have to access the Spark Application, which does not have an Application property. That could be why you are getting the error.
Be sure to import the proper application you want to use:
import spark.components.Application
More info on Spark Application class.

Related

Reading server URL from ActionScript 3 for Cairngorm configuration

I need to read the URL that the browser shows when a Flex application is called because I would to reference it in a mxml configuring Cairngorm remote objects.
The goal I would reach is to automatically configure Cairngorm services from environment to environment (dev,test,qa,prod) without statically set the value in the mxml or other ActionScript. Since the Flex client is deployed in the root of the war of the webapp, it's enough to read where the browser is pointing.
I have written a class that is doing so:
public class ConfigServer {
public function ConfigServer() {
var loaderUrl:String = FlexGlobals.topLevelApplication.loaderInfo.loaderURL;
var urlToSet:String = <loaderURL-string-manipulation>;
_serverUrl = urlToSet;
}
private var _serverUrl:String = '';
public function get serverUrl():String
{
return _serverUrl;
}
}
In my mxml I would do so:
<mx:Script>
<![CDATA[
import org.fao.fapda.util.ConfigServer;
private var configuration:ConfigServer = new ConfigServer();
]]>
</mx:Script>
<mx:RemoteObject
id="userService"
destination="userService"
endpoint= "{configuration.serverUrl}/messagebroker/amf"
showBusyCursor="true"
requestTimeout="100"
/>
But whenever I call the ConfigServer constructor and for every (known to me) technique I applied (statics or singletons or public ro so on), I have always had the same error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at org.fao.fapda.util::ConfigServer()[C:\dev\workspaces\FAPDA\trunk\FAPDA-client\src\org\fao\fapda\util\ConfigServer.as:8]
Cairngorm services initialization is done as follow:
<fx:Declarations>
<cut/>
<services:FAPDAServices id="services"/>
<cut/>
</fx:Declarations>
and the problem is that FAPDAServices.mxml is read runs before FlexGlobals is valid...
Is there a point in the Flex Application lifecycle where such loaderURL is defined so that I can construct ConfigServer? When in startup events that initialization in done?
I confess I'm a Flex epic rookie, so it's possible I'm completely wrong on this.
Best regards
I can't directly answer your question, but hopefully I can point you in the right direction until someone more experienced sees your question.
Create an event handler for the application tag's creationComplete event (or the highest mxml component tag if this is your own custom component) and instantiate ConfigServer there. It is generally neater to do initialization there since it is the last stop before anything is displayed on screen. You can read up more about the event in the adobe live docs. My paraphrasing should never be considered a replacement for official documentation.
You can also use the trace() statement to output text to the console to help you debug the order of execution and whether or not an object has been instantiated. Once again you can check the adobe live docs for more info.
Good luck.

Getting ahold of the Application to call its method

In my Flex 4.5 application I have a TitleWindow Settings.mxml, which is popped up by the PopUpManager.
Once the user has changed some settings, I not only need to save them to a SharedObject, but also to apply them to the main Application itself - so that the changes are visible to the user immediately.
For example I need to call its method hideApp(somevalue);
The spark.components.Application does not seem to have any static/singleton methods to get ahold of it.
So how do you do it?
And I also wonder how to declare, that an MXML file implements one or several interfaces?
package {
public interface Hiddable {
function hideApp(value:Number):void;
}
}
I'm asking this, because besides the main Application I have a SettingsTest.mxml Application in my project for "unit testing" that particular functionality.
Thank you! Alex
Yes it does:
FlexGlobals.topLevelApplication
though I would recommend you use events to avoid tight coupling.
As for the question about interfaces: use the attribute implements
<s:Component ... implements="IClassA,IClassB" ... />
About implementing of interfaces in MXML components see the following documentation.
What about passing changed data back from your pop up window to the application I recommend you to use Observer pattern with Flash event model something like the following:
var myWindow:MyWindow = MyWindow(PopUpManager.createPopUp(this, MyWindow));
myWindow.addEventListener(MyWindowEvent.SUBMIT, myWindowSubmit);
private function myWindow(event:MyWindowEvent):void
{
// Unsubscribing from events
var myWindow:MyWindow = MyWindow(event.currentTarget);
myWindow.removeEventListener(MyWindowEvent.SUBMIT, myWindowSubmit);
// Changed data is passing with custom event object
someData = event.someData;
}
And you should implement your custom event for that (MyWindowEvent in my pseudo code) and fire it from your TitleWindow component. You can read more about implementing custom event in documentation.

access mxml component from external actionscript file

i'm trying to access an mxml component from my external as file. e.g
main.mxml:<br>
<code>[mx:text id="myText" />]</code>
file.as:<br>
<code>var mainM:main = new main();
mainM.text.visible = true;</code>
I get the following error:
[TypeError: Error #1009: Cannot access a property or method of a null object reference]
Any suggestions on how to approach it better.
The ID of your component instance becomes a member of your application and can easy be accessed like so
import mx.core.Application;
mx.core.Application.application.myText.visible = true;
An additional answer is that when you create a new Flex component (new myFlexComponent()), the child UI components are not created until a CREATION_COMPLETE call is invoked, indicating the component is fully created. In the case of application, there is only one, and its automatically created by the framework, and referenced by (Application.application) as stated above.
For example, if your variable was a simple class variable (e.g. myDate:Date), you could access it via the above syntax

Extending Flex FileReference class to contain another property

I want to extend the FileReference class of Flex to contain a custom property. I want to do this because AS3 doesn't let me pass arguments to functions through event listeners, which makes me feel sad, so I need this property to exist on the event target, so I can access it.
I also want to be able to cast extant FileReference objects to this class without any fuss. I have:
var fr:SmxFR = e.target as SmxFR
and I want that to work; right now it just returns null.
A blank, newly instantiated SmxFR object has the extended property in place, but all of its inherited properties and objects return Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
This is the class I am using, SmxFR.as:
package
{
import flash.net.FileReference;
public class SmxFR extends FileReference
{
public var housenum:String = "";
public function SmxFR()
{
super();
}
}
}
Kept it as straightforward as I could, really. Can someone please help me figure this out? Thanks.
Edit:
Per request, this is the instantiation which results in the aforementioned error in all inherited objects:
var fr:SmxFR = new SmxFR();
I get living handle property from that, and all other (that is, inherited) properties throw Error #2037.
So, maybe what I want to do is going to require overriding FileReferenceList? If the original objects must be instantiated to SxmFR, that's what I'll have to do, since I'm using FRL to allow the user to select multiple files at once. Are you guys sure there is no way to fast from a FileReference to my class?
You can totally pass objects via event listeners, it's just done in a specific way. I'd learn to do it correctly, rather than trying to extend a core library which could cause you problems later if you make a small mistake.
My solution: instead of extending FileReference, extend Event and add your properties to that.
var myEvent:MyExtendedEvent = new MyExtendedEvent();
myEvent.myCustomProperty = myValue;
dispatchEvent(myEvent);
Then in your handler you just write:
function myEventHandler(e:MyExtendedEvent):void {
trace(e.myCustomProperty);
}
Much more painless to go down this road! The added benefit is that if any other Flash Developer anywhere ever looks at your code they're not going to get hit in the face with a non-standard customized FileReference. :)
When e.target is instantiate as FileReference you can't cast it to SmxFR because it's not in the line of inheritance. In the other way you can a SmxFR Object to FileRefernce.
Extending FileReferenceList is not going to be helpful. FileReferenceList.browse() method creates an array of FileReference object when user selects multiple files - that happens internally (may be in its private methods) and you cannot change that behavior and force it to create SxmFR objects instead. Use custom events as Myk suggested.
This article talks about Sound objects, but may be that's applicable to FileReference objects too. May be you cannot reuse them. Post the code where you use the SmxFr class and get the said error.

Can an Actionscript component listen to its own propertyChange events?

I have a CircleButton class in Actionscript.
I want to know when someone externally has changed the 'on' property.
I try listening to 'onChange' but it never hits that event handler.
I know I can write the 'on' property as a get/setter but I like the simplicity of just using [Bindable]
Can an object not listen to its own events?
public class CircleButton extends UIComponent
{
[Bindable]
public var on:Boolean;
public function CircleButton()
{
this.width = 20;
this.height = 20;
graphics.beginFill(0xff6600, 1);
graphics.drawCircle(width/2, height/2, width/2);
graphics.endFill();
this.addEventListener(MouseEvent.ROLL_OVER, rollover);
this.addEventListener(MouseEvent.ROLL_OUT, rollout);
this.addEventListener('onChange', onOnChange);
}
private function onOnChange(event:PropertyChangeEvent):void {
If you use the [Bindable] tag without specifying an event type, then when the property changes its value, an event of type: PropertyChangeEvent.PROPERTY_CHANGE, which is the string 'propertyChange', will be dispatched.
Therefore, to be able to register to listen to that event, you need to say:
this.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onOnChange);
The reason why your listener function was never called is that the event type was not correct.
Note that the listener method will be called when any of the variables marked as Bindable in your class changes, not only 'on'. This event comes with a property called 'property' that indicates which variable was changed.
To avoid being called on each Bindable variable, you need to specify an event in the [Bindable] tag:
[Bindable(event="myOnChangeEvent")]
and dispatch that event manually when you consider that the property is changing (ie: in the setter), though that didn't seem to be what you wanted to do.
You could use BindingUtils.bindSetter()
An example is found here.
Just because it is possible for something to bind to the variable, doesn't mean something is bound to the variable. It's a bit like the event system - just because something can dispatch an event doesn't mean anything is listening.
The Classes around which the Flex binding is based are BindingUtils and ChangeWatcher. When you bind directly in MXML (which just gets converted to AS3 by the compiler) it uses these classes behind the scene to actually establish the binding. I've dug around in ChangeWatcher before and when it looks through the list of potentially bindable items it only dispatches if some object is actually listed as a listener. The whole binding system is a smart wrapper around the event system actually.
The semantics of binding in AS3 instead of MXML are different. Subtle differences (like chaining to child properties of Objects) that just work in MXML require work in AS3 to duplicate the behaviour (probably a result of the code generation between MXML to AS3).
Have a look at this Adobe doc for a little info on ChangeWatcher in AS code.
Personally - I do not use binding outside of MXML since I feel it is clumsy. I would suggest you write a setter function instead since it is more predictable (and very likely performant). I also suggest you read through the source code for ChangeWatcher and BindingUtils. That is definitely some of the most advanced AS3 you are likely to read.
One of my favorite approaches is the Observe class which is found here. It is essentially using a setter but it is a nice repeatable approach.

Resources