Getting ahold of the Application to call its method - apache-flex

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.

Related

Unable to dispatch custom event in flex mobile application

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.

Setting the WebServiceWrapper endpointURI at run time

I'm in the middle of switching from Flex Builder 3 to Flash Builder 4, and one of the problems I have run into is that support for web services in 4 is substantially different. In both IDE's I am able to import a WSDL for my web service and it will generate the appropriate client classes for communicating with the service. The generated code in each is different.
In my Flex3 code I was able to access the endpointURI property of the mx.rpc.soap.AbstractWebService, but in the Flex4 code that is generated, the new class extends com.adobe.fiber.services.wrapper.WebServiceWrapper which does not have the endpointURI property.
My project has mulitple game servers and the player picks which server they want to play on. In the past if the player wanted server 1, I would set the endpoint URI to http://game1.server.com/service.asmx, and like wise if they wanted server 2 I would set the endpoint to http://game2.server.com/service.asmx.
What am I looking for to accomplish this in Flash Builder 4?
Short Answer:
var s:ClassThatExtendsWebServiceWrapper = new ClassThatExtendsWebServiceWrapper;
s.serviceControl.endpointURI = 'http://service.com/service.asmx';
Long Answer:
Well I finally found a solution. Adobe seems to have made this much harder than it should have been.
Web Service classes that are generated by Flash Builder 4 extend the com.adobe.fiber.services.wrapper.WebServiceWrapper. WebServiceWrapper has a property called serviceControl that can be used to control the service. The problem is that not all the members of serviceControl are accessible at the application code level. Lets assume that I have a web service called GameService. When I use the data tool to connect to the web service by providing a WSDL, Flash Builder will create two classes for me automcatically.
internal class _Super_GameService extends
com.adobe.fiber.services.wrapper.WebServiceWrapper
{ ... }
public class GameService extends _Super_GameService
{}
_Super_GameService contains all the automatically generated code to make calls to the web service. GameService contains no code itself, but unlike _Super_GameService, it is public. The idea here is that any enhancements that we need to make can be made to GameService, then later on if we need to update, _Super_GameService can be regenerated, but out changes to GameService will not be overwritten by the code generation tool.
Now this leads us to usage of these generated classes. Typically all I should have to do is create an instance of GameService and call a method on it. In this example DoSomethingAwesome is a method available on the web service.
var gs:GameService = new GameService();
var token:AsyncToken = gs.DoSomethingAwesome();
Now this will call the service using the URI of the service specified in the WSDL file. In my situation I wanted GameService to connect to a different URI. This should have been simple, but things fell apart.
My first problem was that viewing the documentation on WebServiceWrapper (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/com/adobe/fiber/services/wrapper/WebServiceWrapper.html) did not render properly in Firefox. So when I was reading the documentation I wasn't getting the full picture. This really needs to be fixed by Adobe.
Viewing the documentation in another browser helped me find out about the serviceControl property of WebServiceWrapper. serviceControl is declared as a mx.rpc.soap.AbstractWebService. AbstractWebService does have an endpointURI property which makes the following code valid.
var gs:GameService = new GameService();
gs.serviceControl.endpointURI = 'http://game1.service.com/GameService.asmx';
The other problem I had is that for some reason the endpointURI property of serviceControl does not appear in the Intellisense context menu. So since I didn't see serviceControl in the online documentation at first, and I didn't see endpointURI in intellisense, I didn't realize the property was there to be set.
If you look at the source for AbstractWebserivce, (http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/soap/AbstractWebService.as) there doesn't seem to be an Exclude tag to explain why endpointURI does not appear in the Intellisense context menu. So I don't know what is going on there.
You should be able to override the endpointURI on the WebService. But I'm not sure where to do that with the generated code since I use <s:WebService/>.
This is the only way I could get it to work, in the generated stub for your service:
import com.adobe.fiber.core.model_internal;
Also:
/**
* Override super.init() to provide any initialization customization if needed.
*/
protected override function preInitializeService():void
{
_needWSDLLoad = false; // to prevent loading the default WSDL
super.preInitializeService();
// Initialization customization goes here
wsdl = "http://localhost/yourservice?wsdl";
_needWSDLLoad = true;
model_internal::loadWSDLIfNecessary();

ActionScript Interfaces with custom namespaces

Is there any way to get interface to play along with custom namespace? Example follows.
IHeaderRenderer.as:
public interface IHeaderRenderer{
function set header(value:IHeader):void;
function get header():IHeader;
}
HeaderRenderer.as
import fi.test.internalNamespace;
public class HeaderRenderer implements IHeaderRenderer{
internalNamespace function set header(value:IHeader):void{
// do something
}
internalNamespace function get header():IHeader{
// do something
}
}
This gives you the basic compiler error:
1044: Interface method get header in namespace fi.gridutils.headerrenderers:IHeaderRenderer not implemented by class fi.gridutils.headerrenderers.implementation:HeaderRenderer.
Why is this needed, you might ask. I'm developing a component, where the header accessors should not be directly visible to the components end user (developer), but if the developer wants to create his own Renderer he should know that they are needed. This is because the parent component will use these accessors to give the custom renderer the data it needs to render the header correctly.
Now to my mind there seems to be only three choices:
1) use public access control. This has the setback that the end developer will see accessors, which should not be directly accessed by him. Plus they add unnecessary clutter as they appear in auto-complete.
2) do not use interface. This means the end user has pretty poor options of developing the component further.
3) use the interface, but omit the accessors that use internalNamespace. Now the end developer will not know that he should add also header accessors to his custom headerrenderer class, which ends up in Flash Player giving following error to the developer in runtime:
Cannot create property internalNamespace/::header on fi.gridutils.headerrenderers.implementation.HeaderRenderer.
Sorry for all the blabbing. Any cunning ideas how this kind of situation could be handled?
In ActionScript, the interface methods need to be public. What good is an interface, if you can't guarantee the component using it can access the relevant interface methods?
that said, you can use the exclude metadata to prevent properties from showing up in code hinting.
Something like this:
[Exclude(name="header", kind="property")]
More info

How to implement callbacks in Java

I have a class called CommunicationManager which is responsible for communication with server.
It includes methods login() and onLoginResponse(). In case of user login the method login() has to be called and when the server responds the method onLoginResponse() is executed.
What I want to do is to bind actions with user interface. In the GUI class I created an instance of CommunicationManager called mCommunicationManager. From GUI class the login() method is simply called by the line
mCommunicationManager.login();
What I don't know how to do is binding the method from GUI class to onLoginResponse(). For example if the GUI class includes the method notifyUser() which displays the message received from theserver.
I would really appreciate if anyone could show how to bind methods in order to execute the method from GUI class (ex. GUI.notifyUser()) when the instance of the class mCommunicationManager receives the message from the server and the method CommunicationManager.onLoginResponse() is executed.
Thanks!
There's two patterns here I can see you using. One is the publish/subscribe or observer pattern mentioned by Pete. I think this is probably what you want, but seeing as the question mentions binding a method for later execution, I thought I should mention the Command pattern.
The Command pattern is basically a work-around for the fact that java does not treat methods (functions) as first class objects and it's thus impossible to pass them around. Instead, you create an interface that can be passed around and that encapsulates the necessary information about how to call the original method.
So for your example:
interface Command {
public void execute();
}
and you then pass in an instance of this command when you execute the login() function (untested, I always forget how to get anonymous classes right):
final GUI target = this;
command = new Command() {
#Override
public void execute() {
target.notifyUser();
}
};
mCommunicationManager.login(command);
And in the login() function (manager saves reference to command):
public void login() {
command.execute();
}
edit:
I should probably mention that, while this is the general explanation of how it works, in Java there is already some plumbing for this purpose, namely the ActionListener and related classes (actionPerformed() is basically the execute() in Command). These are mostly intended to be used with the AWT and/or Swing classes though, and thus have features specific to that use case.
The idiom used in Java to achieve callback behaviour is Listeners. Construct an interface with methods for the events you want, have a mechanism for registering listener object with the source of the events. When an event occurs, call the corresponding method on each registered listener. This is a common pattern for AWT and Swing events; for a randomly chosen example see FocusListener and the corresponding FocusEvent object.
Note that all the events in Java AWT and Swing inherit ultimately from EventObject, and the convention is to call the listener SomethingListener and the event SomethingEvent. Although you can get away with naming your code whatever you like, it's easier to maintain code which sticks with the conventions of the platform.
As far as I know Java does not support method binding or delegates like C# does.
You may have to implement this via Interfaces (e.g. like Command listener.).
Maybe this website will be helpful:
http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
You can look at the swt-snippets (look at the listeners)
http://www.eclipse.org/swt/snippets/
or you use the runnable class , by overwritting the run method with your 'callback'-code when you create an instance

Best Practise to Define and update MXML component in Flex application

A Flex components values are initialized by init method.
In an application flow,
How to refresh a mxml component data value ; as init is called at the start up itself only.
Example of mxml component may be
as simple as button label or text
as complex as repeater whose data provider is a web service
( means a fresh quesy should be made to pull the data and refresh the dataprovider of repeater )
If the dataprovider is a collection or an array it will update itself as items are added to or deleted from the collection. You can listen to the CollectionEvent.CollectionChange event to see when a collection changes.
I'm not really sure what you mean though? Are you on about binding?
If you want to re-init the whole control, you could create an "reset" event and have the handler for the reset execute the same behavior as the init code.
That's the best I can do without more details...
you should create yourself setters and getters for the properties you want to modify and a refresh is required afterwards. for example:
private var _tmp : String = '';
public function set tmp(val : String) : void {
this._tmp = val;
this.doOtherDataRefreshNeeded();
}
public function get tmp() : String {
return this._tmp;
}
and this way, everytime the code that uses this component and needs to update it's tmp property. the setter will be called and in there a lot of other stuff can happen beside assigning the value.
for simple mxml components as texts and inputs, use bindings {} for their data values. those should update as soon as the data changes. if not, call .invalidateNow() method on them to force update.
use ValidateNow() method in mxml component in updating method

Resources