LocalConnection: communicate between flex 4.1 and flash as2 - apache-flex

I'm trying to communicate between a flex 4.1 application to a flash action script 2 application using LocalConnection.
flash application
contains a button called btn01 and the following code:
var a:LocalConnection = new LocalConnection();
btn01.onPress = function() {
trace("button clicked");
a.send("abcde","test");
}
you can see here that it sends a test command to the connection named 'abcde'.
flex application
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function init():void {
var a:LocalConnection = new LocalConnection();
a.client=this;
a.connect("abcde");
}
public function test():void {
Alert.show("test");
}
]]>
</fx:Script>
<mx:SWFLoader source="/location/as2-flash-file.swf" />
as you can see, in the flex application i connect to LocalConnection named 'abcde' and i set the client to 'this' which means that all the public functions can be executed from the LocalConnection.
the SWFLoader element loads the as2 flash file.
whenever i click the button i do see the trace message but the function test does not get executed on the flex application. any ideas?
update
both applications sit on the same domain, on the localhost actually so no need for allowDomain usage and both applications are web based.

Documentation says AS2 and AS3 LocalConnections should communicate no problems.
Do you need to look into the allowDomain method? Do you need to put a crossdomain.xml file in place? If you do have swfs on two different domains, pay special attention to the send method documentation, because you you have to add additional info to the send method's connection name.
Are they both browser based applications? I not, look into AIR

I created the LocalConnection variable within the init() scope, so when the function ended the localconnection was destroyed. the solution is just to declare the variable outside of the init function.
public var a:LocalConnection;
private function init():void {
a = new LocalConnection();
a.client=this;
a.connect("abcde");
}

Related

UIComponent in a test case is null

I have this App.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Button id="bt" label="click me"/>
</s:Application>
And this test case:
package flexUnitTests
{
import flexunit.framework.Assert;
public class AppTest
{
[Test]
public function testApp():void
{
var app:App = new App();
Assert.assertNotNull(app.bt);
}
}
}
But app.bt is null. I want to access the button :(
Short Answer:
The life cycle methods have not run on app; so no createChildren() method was executed in order to create the child component of bt.
Longer Answer:
Things get slightly more complicated with the main application file, as it there is no higher level Flex component in the display hierarchy. I'm unclear on all specifics, but..
I think the Flex Compiler does some magic to set up this component--and the Flex Framework--that help makes the whole app work. You are, in essence, bypassing that work by creating your own instance of the component.

Flash builder 4.6 - code behind approach

I'm trying to figure out the right approach for "Code behind" using flash builder for a mobile app:
I'm creating a flex mobile AIR project (Based on the "Tabbed view" template)
setting my UI in design mode
now I want all the logic to be in a separate class that will change the UI look accordingly
Sounds easy, however I can't really get the approach for doing it, any help is appreciated :)
Update:
main app:
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="160">
<s:ViewNavigator label="a" width="100%" height="100%" firstView="views.aView"/>
<s:ViewNavigator label="b" width="100%" height="100%" firstView="views.bView"/>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:TabbedViewNavigatorApplication>
view A:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="a">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Label id="txt" x="280" y="139" text="Label"/>
</s:View>
So now I want MyClass to change txt textField according to my logic, what is the right approach?
An elegant way would be implementing IMXMLObject. When implementing this interface, the IMXMLObject#initialize method will take the component (named document of type Object) and an optional id (of type String) as arguments and u can easily implement this pattern. The big advantage is, that you use composition over inheritance and when using interfaces, you can use it as some sort of type save mix-in as view behavior:
package net.icodeapp.examples.views
{
import flash.events.MouseEvent;
import mx.core.IMXMLObject;
import mx.events.FlexEvent;
public class ViewBaseModel implements IMXMLObject
{
//-------------------------------------------------------------------------
//
// Properties
//
//-------------------------------------------------------------------------
private var _id:String;
private var _viewBase:ViewBase;
protected function set viewBase(value:ViewBase):void
{
_viewBase = value;
if (!_viewBase)
throw new ArgumentError('View must be instance of ViewBase');
if (!_viewBase.initialized)
_viewBase.addEventListener(FlexEvent.CREATION_COMPLETE, viewBase_creationCompleteHandler, false, 0, true);
else
viewCreationCompleted();
}
//-------------------------------------------------------------------------
//
// Constructor
//
//-------------------------------------------------------------------------
public function ViewBaseModel()
{
}
//-------------------------------------------------------------------------
//
// Methods
//
//-------------------------------------------------------------------------
public function initialized(document:Object, id:String):void
{
viewBase = document as ViewBase;
_id = id;
}
private function viewCreationCompleted():void
{
_viewBase.addEventListener(MouseEvent.CLICK, viewBase_clickHandler);
}
//-------------------------------------------------------------------------
//
// Event Handler
//
//-------------------------------------------------------------------------
private function viewBase_creationCompleteHandler(event:FlexEvent):void
{
viewCreationCompleted();
}
private function viewBase_clickHandler(event:MouseEvent):void
{
// todo: do some action
}
}
}
The model is initialized and references are set by the framework. When taking a peek at the generated ActionScript code you'll see, that IMXMLObject#initialize it called in the constructor after the model is instantiated.
<?xml version="1.0"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:views="net.icodeapp.examples.views.*">
<fx:Declarations>
<views:ViewBaseModel/>
</fx:Declarations>
</s:Group>
The model would receive by events by the view and can call methods on it.
All you do is make an AS file that has the same base class as whatever your MXML object was initially set up as, for example if it's a VGroup make MyBaseClass extends VGroup, then change the VGroup to MyBaseClass.
Example
[Main.mxml]
<main:MainBase
xmlns:main="*"
...>
</main:MainBase>
[MainBase.as]
public class MainBase extends Application
Think of your Code Behind as a base class (or an Abstract Class). In an Abstract Class, it is really common for the actual implementation of methods or the "real objects" behind properties to be left to the extending class(es) to supply.
This is exactly like what you do when you set a base class in Flash to your custom Class, but the actual member objects (buttons, etc.) are provided on the stage of the MovieClip whose library instance is linked to your clip.
For more on code behind, check out my blog post here. If you'd like to check out the code for the template component described there, look here. Though template components are less useful in the Spark world (IMO).

Flex and Parsley Logging

i'm looking for a possibility to log messages in my flex 4.5 Project. This should cover errormessages in remoteClasses, errorHandler or messages typing by hand.
After reading a lot of webpages, the solution from parslay looks good. i want to switch to this framework anyway.
the benefit is the possibility to configure the logging behavior at runtime. but i don't understand the documentation. perhaps because I'm brandnew in parsley. Also google has no fitting result.
Do you have already did this and it is possible for you to give me a few code snippets.
Thanks a lot
Frank
EDIT:
Because of J_A_X justified criticism, i add my code, because i have partially succeeded.
First we need a config file, because i want to configure the logging behavior in runtime. This is a simple xml-file in the project root.
<?xml version="1.0" encoding="UTF-8"?>
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:log="http://www.spicefactory.org/parsley/flex/logging"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.3/parsley-core.xsd
http://www.spicefactory.org/parsley/flex/logging
http://www.spicefactory.org/parsley/schema/2.3/parsley-logging-flex.xsd"
>
<log:target level="info" type="components.SocketTarget">
</log:target>
</objects>
This is my Application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600"
initialize="onAppInitiallize(event)"
xmlns:parsley="http://www.spicefactory.org/parsley"
>
<fx:Script>
<![CDATA[
import mx.controls.Label;
import mx.events.FlexEvent;
import mx.logging.Log;
import org.spicefactory.lib.logging.LogContext;
import org.spicefactory.parsley.flex.logging.FlexLoggingXmlSupport;
protected function onAppInitiallize(event:FlexEvent):void
{
FlexLoggingXmlSupport.initialize();
LogContext.getLogger(this);
//Log.getLogger("myCat").info("MyInfo");
}
protected function button1_clickHandler():void
{
Log.getLogger(this.toString()).info("myMessage");
Log.getLogger(this.toString()).fatal("myMessage");
}
]]>
</fx:Script>
<fx:Declarations>
<parsley:ContextBuilder>
<parsley:XmlConfig file="config.xml"/>
</parsley:ContextBuilder>
</fx:Declarations>
<s:Button click="button1_clickHandler()" label="SendLogToParsley" />
</s:Application>
At this point, the logging will work in the console of the flex builder, because parsley uses by default the TraceTarget. Now, i want to send my Logfiles to a socket. I wrote a litte rough SocketTarget.
package de.axurit.components
{
import flash.net.Socket;
import mx.logging.AbstractTarget;
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;
public class SocketTarget extends AbstractTarget
{
private var _host:String;
private var _port:int;
private var _socket:Socket;
public function SocketTarget(host:String = "localhost",port:int=8085)
{
_host = host;
_port = port;
_socket = new Socket (host,port);
super();
}
override public function logEvent (event:LogEvent):void
{
trace ("logevent" + event.message);
_socket.writeUTF(event.message + String.fromCharCode(13));
_socket.flush();
}
}
}
In the parsley documentation i can see the comment
The default target type created by this tag is a TraceTarget. You can
explicitly declare other target types:
If i add the type-attribute, i receive a Errormessage "One or more errors in BootstrapProcessor". The same as i received after a typo.
Can you give me some hints, how i can send my logs to a socket destination?
You're creating the socket, but never actually connect it. Plus, if you're going to make a log target, make your class extend trace target and override the log function.

Deployed flex applet not processing web service results

When I test my deployed app in a browser the popup window continues to be displayed even after it should be closed. Everything works as expected when debugged in Flash Builder 4.
Following is currently what's happening: the request is sent to my restful web service, which processes the request, (seemingly) the ResultEvent is called which in turn dispatches the profileEvt dynamic event that changes the view state. However, the popup window does not get closed and the applet gets 'stuck.'
Anyone know what could be the problem? Below are the flex applet web service event listeners/handlers:
webService.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void
{
var rawData:String = String(event.result);
var profileEvt:DynamicEvent = new DynamicEvent("profileSaved", true);
profileEvt.data = JSON.decode(rawData).profile;
dispatchEvent(profileEvt); // Dispatch profile saved event
_progressPopUp.closePopUp();
dispatchEvent(event); // Dispatch submit profile button clicked
});
webService.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void
{
Alert.show("Could not create profile; please try again later.\n" + event.message, "Status");
_progressPopUp.closePopUp();
});
var params:Object = {"profile" : profile};
try
{
_progressPopUp = PopUpManager.createPopUp(this, com.profs.ui.components.ProgressPopUp, true);
_progressPopUp.eventSource = webService; // Set source of progress events
webService.send(JSON.encode(params));
}
NOTE:
com.profs.ui.components.ProgressPopUp is a custom component; the code for it is below:
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" layout="absolute" width="300" height="200" showCloseButton="false" title="Status" creationComplete="init()">
<fx:Declarations></fx:Declarations>
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
[Bindable] public var eventSource:Object;
private function init():void
{
PopUpManager.centerPopUp(this);
}
public function closePopUp():void
{
PopUpManager.removePopUp(this);
}
public function completionHandler(event:Event):void
{
closePopUp();
}
]]>
</fx:Script>
<mx:ProgressBar id="progressBar" indeterminate="true" mode="event" source="{eventSource}" complete="completionHandler(event)" verticalCenter="0" horizontalCenter="0"/>
</mx:TitleWindow>
I am not familiar with the com.profs.ui.components.progressPopUp component, but it is possible that the closePopUp() method has a bug in it. You could try to remove the ProgressPopUp directly using the PopUpManager method. For example instead of:
_progressPopUp.closePopUp();
try
PopUpManager.removePopUp(_progressPopUp);
I also don't know off the top of my head what the rules for closures are (i.e. at which point is the _progressPopUp variable copied into the ResultEvent.RESULT event handler. You could try moving that particular event handler below the line where you actually created the _progressPopUp instance.

A question on capturing the button click event in ANOTHER mxml file

this seems to be an interesting question to be discovered in Flex.
I registered a very simple button event listener in A.mxml:
<mx:Script><![CDATA[
import mx.controls.Alert;
public function Handler():void
{
Alert.show('click event occured');
}
]]></mx:Script>
<mx:Button label="{resourceManager.getString('resources', 'button.startLab')}"
id="nextStepButton" click="Handler()" />
It works fine when clicking the button everytime.
Now I want to have something interesting,that is,I want to capture this buttonClick Event in another mxml file,say B.mxml and do something in B.mxml instead of A.
I am bit stuck on this,hope you could give me some hint and help,thanks a lot.
There are a number of approaches to this problem. The simplest (and least object-oriented) is to have A be aware of B, or vice versa. In that case you can just add a listener. In B you could say a.nextStepButton.addEventListener(MouseEvent.CLICK, myHandler), or in A you could do this.nextStepButton.addEventListener(MouseEvent.CLICK, b.myHandler). (When one component is instantiated, you have to set a reference to it on the other component.)
One step better would be to dispatch a custom event that bubbles, with one of the components still aware of the other. In B: a.addEventListener(CustomNavigationEvent.NEXT_CLICK, myHandler), or in A: b.addEventListener(CustomNavigationEvent.NEXT_CLICK, myHandler).
Taking it further, you could just let the event bubble to the top (the SystemManager) and add your listener to the SystemManager. This way B is not aware of A at all. In B: this.systemManager.addEventListener(CustomNavigationEvent.NEXT_CLICK, myHandler).
Taking it even further, you can implement your own version of an event broadcaster, which is just a third object that is accessible by any component, usually implemented as a singleton, that takes listener registrations and accepts event dispatches, then broadcasts that event to registered listeners.
Hope that helps.
EDIT: Here's some code for doing it the first way:
In A.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="onCreationComplete(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
public var b:B;
private function onCreationComplete(e:FlexEvent):void {
// Note that you have to have a public onClick handler in B
this.myButton.addEventListener(MouseEvent.CLICK, b.onClick);
}
]]>
</fx:Script>
<s:Button id="myButton"/>
</s:Group>
You need to make A aware of B in the container that declares instances of both A and B:
MXML:
<mypackage:A id="aComponent" b="bComponent"/>
<mypackage:B id="bComponent"/>
ActionScript equivalent:
var aComponent:A = new A();
var bComponent:B = new B();
aComponent.b = bComponent;

Resources