we've got two applications (not modules, two independent applications!): A and B. both are Parsley-managed and we'd like to embed B in A using SWFLoader (but, and i stress that, we don't want to "connect" these applications using Parsley, we just want to do normal Flash embedding) .
that's embed code:
<fx:Script>
<![CDATA[
[Bindable]
private var childDomain:ApplicationDomain =
new ApplicationDomain(ApplicationDomain.currentDomain);
]]>
</fx:Script>
<mx:SWFLoader width="100%" height="100%" source="B.swf"
complete="initNestedAppProps(SWFLoader(event.currentTarget).content);"
loaderContext="{new LoaderContext(false, childDomain, SecurityDomain.currentDomain)}"/>
and it works when i embed B in a dummy app without Parsley.
however, when i copy-paste that embed code in live application A, Parsley throws this famous error:
ReferenceError: Specified ApplicationDomain does not contain the class _B_mx_managers_SystemManager
even if the view that contains embedding code is not Parsley-configured (and doesn't have <Configure/> tag).
i can't post this on Parsley forums unfortunately and googling didn't help as it seems people don't do application embedding too often.
so the question is, why does this error happen (Parsley shouldn't care about stuff in embedded application, should it?) and how can tell Parsley to properly use my childDomain?
The problem is that Parsley is bubbling events up the display list so that a context can use them to inject properties etc.
Despite the fact your sub application is in a separate application domain, events can still bubble up from the swf loader's child to the parent and so on.
What is happening is that your sub application is bubbling events that are getting handled by your shells (or wrapper/loader applications) context, however when parsley then tries to reflect on this object it can't because the object doesn't exist in it's application domain.
The solution is to stop these events getting to your shell application's parsley context. You can do this a number of ways, for example you could just add listeners for the events and stop their propagation. However this would mean you would have to add listeners for all Parsley events, which could change in the future. A better solution is to create a new context in your SWFLoader’s parent that has an autowireFilter that returns ViewAutowireMode.NEVER for displayObjects passed to it.
This context will stop them bubbling any further and will stop parsley reflecting on them, and therefore stop the problem with them not being in the application domain.
See: org.spicefactory.parsley.core.view.impl.DefaultViewAutowireFilter
org.spicefactory.parsley.core.builder.impl.DefaultCompositeContextBuilder
http://opensource.powerflasher.com/jira/browse/PSL-587
Hope this helps.
the above answer is correct.
in our case i solved the problem by writing a flex module and using ModuleLoader instead of SWFLoader, which is nicely integrated with Parsley.
Related
I have been using Flex / Flash Builder for a number of years. The latest release of Flash Builder (4.7) seems to come with quite a few problems, the biggest of those being:
Does not detect component IDs in MXML. For example, you cannot Find Usages of the ID of a component. Keeping the cursor on the ID of a component does not even mark occurrences of the ID. Instead, it marks occurrences of the actual id words in the MXML.
Extremely slow.
I am seriously evaluating moving over to IntelliJ IDEA 12, especially after reading many experienced Flex devs raving about it and recommending it.
I tried it. It took me a while to get to terms with the new terminologies of the IDE (made easy by this doc and very helpful support personnel at JetBrains).
I was able to setup my (large) projects in IDEA with Adobe Flex 4.6 SDK and got it to compile fine. But I noticed many "errors" highlighted in my AS files which are all actually false alarms.
The ActionScript editor doesn't seem to recognise the objects defined in MXML. Apparently, this is a known bug in IDEA (tracked here). And this bug has existed for more than 2 years!
Quoting the JetBrains support personnel:
I must admit that highlighting of ActionScript files which do not contain classes, but instead included in mxml as <fx:Script source="some_file.as"/> is probably the only weak part of IntelliJ IDEA code highlighting. False error highlighting will go away if you embed AS code inside CDATA of <fx:Script/> instead of referencing as external *.as file. Though I understand that this is not always desired.
I'm afraid the fix won't go into 12 release because the release is very soon and the fix is too risky. Priority of the issue depends on votes and user feedback. So far we have only 2 votes (http://youtrack.jetbrains.com/issue/IDEA-52598) and as the fix is pretty complex we still haven't implemented it thinking that this is a rare use case. I hope to fix it in one of 12.x update releases.
My project is a huge one, with huge MXML files and even more huge AS code for each MXML. So, for organisation purposes, I need to logically split them into smaller files. So, merging the AS code with the MXML is not practical. The false error highlighting just drastically reduces the readability of the code. Also, it does not allow Control / Command-clicking component IDs in AS code to quickly navigate to the definition of the component in MXML (which, incidentally, is now broken in FB 4.7 as well, but worked well in FB 4.6).
This bug in IDEA is unfortunately a deal-breaker for me. But I am wondering how other Flex devs are able to overcome / work around this seemingly critical bug.
It seems unbelievable to me that just 2 people have been affected by this bug, especially with so many Flex devs recommending IDEA. Maybe I am doing something wrong?
All you Flex developers, I would appreciate your thoughts.
UPDATE
This is in response to RIAStar's excellent and detailed answer. But it doesn't quite help me completely. Let me explain why and how I use <fx:Script source>. I am using Flex 4.x, with almost only Spark components.
Suppose a brand new Flex project. The main application is an MXML file.
In this MXML file, suppose I have a signup form.
On editing the form (in each field), suppose I have to run validations and enable the Submit button only if the form is completely valid. This would mean I need to assign change event handlers to the form items. The event handlers is AS code.
Suppose there is a username field which needs an on-type uniqueness check, by calling the server asynchronously. The server communication code is also AS code.
And then of course, there is the Submit button handler, which is also AS code.
I usually put all the AS code in separate .as files and include it in the MXML using <fx:Script source>. This AS code is usually quite heavy, with a lot of functional and behavioural logic. Many times, based on user action, even the components in the MXML and layout of the elements is modified through this AS code.
If I understand you guys right, none of this event handler code should be in these MXML script files. So, where should it be? How do you guys do it? I am not sure how the Spark Skinning architecture has anything to do with this.
Since I can't think of a gentle way of putting this, I'll just be blunt: I'm afraid the reason only two people think this is a critical bug, is that most seasoned Flex developers will agree that using <fx:Script source="some_file.as"/> is bad practice.
You effectively create two files that represent one class. From a readablity POV, which you seem concerned about, that's not a good move. One of these files (the .as file) is just a bunch of functions that cannot exist in their own right: they are tightly coupled to another file/class, but just looking at the .as file there is no way of knowing which class it is coupled to. Of course you can use some kind of naming convention to work around this, but in the end ActionScript/Flex is supposed te be used as a statically typed language, not a scripting language relying on mixins and naming conventions (don't get me wrong: I'm not saying scripting languages are bad practice; it's just not how ActionScript was conceived).
So what are your alternatives?
I suppose the main reason behind this construct is that you wish to separate MXML from ActionScript code, or in more abstract terms: separate the view from the logic. Fortunately this can be achieved in a few other, cleaner ways. Which solutions are available to you depends whether we're talking Flex 3 (or earlier) or Flex 4.
I realise that you may not have time to refactor your code to one of the proposed solutions, but I didn't want to leave you with just a "that's not good practice" answer.
Flex 3 (mx)
Code behind: A lot of developers used the so-called "code behind" pattern to separate their logic from their view. You can find plenty of information on the topic by Googling "flex code behind". I don't need to repeat all that in here. I'm not much of a fan of the concept because it relies heavily on inheritance and the two resulting classes are still pretty tightly coupled, but at least we're talking two classes. If you design your architecture well, you may even be able to reuse some of your base classes.
Compose model en controller: I used to create a separate "presentation model" class and a "controller" class for each MXML view and then use it something like this:
<!--MyView.mxml-->
<mx:VBox>
<m:MyModel id="model"/>
<c:MyController model="{model}" view="{this}"/>
...
</mx:VBox>
MVC purists won't like this, but it worked pretty well for me in thencontext of Flex applications.
Later when Direct Injection supporting frameworks (like Parsley) made their appearance, I could use injection to wire all those classes instead of hard-wiring them like in this example.
MVC frameworks: My knowledge of this topic is sparse (because in my opinion Flex is a very decent MVC framework that requires no third-party additions, but that's another disussion), but in short: they can help you separate logic from view in a clean way.
Flex 4 (Spark)
With Flex 4, the Spark skinning architecture was introduced, which allows for very nicely separated view and logic. You create a so-called 'host component' class in plain ActionScript, which contains all of the behavioural code, and a 'skin' class in MXML which defines the visual representation of the component. This makes designing reusable components very easy.
As per your request, here's a simplified example of how you might use Spark skinning to create your signup form.
Let's start with the skin class since it's easy to understand. It's just a form with some input fields. The HostComponent metadata tells the skin it's supposed to work together with the SignUp host component.
<!--SignUpSkin.mxml: the visual representation-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("net.riastar.view.SignUp")]
</fx:Metadata>
<s:Form>
<s:FormHeading label="Sign up"/>
<s:FormItem label="User name">
<s:TextInput id="userInput"/>
</s:FormItem>
<s:FormItem label="Password">
<s:TextInput id="passwordInput" displayAsPassword="true"/>
</s:FormItem>
<s:Button id="submitButton" label="Submit"
enabled="{hostComponent.canSave}"/>
</s:Form>
</s:Skin>
And now the host component in pure ActionScript. It has to extend SkinnableComponent to be able to use our skin (there's also SkinnableContainerwhich I've just recently explained in this question: Flex mxml custom component - how to add uicomponents?, but we won't be needing that here).
public class SignUp extends SkinnableComponent {
[SkinPart(required="true")]
public var userInput:SkinnableTextBase;
[SkinPart(required="true")]
public var passwordInput:SkinnableTextBase;
[SkinPart(required="true")]
public var submitButton:IEventDispatcher;
[Bindable]
public var canSave:Boolean;
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
switch (instance) {
case userInput:
userInput.addEventListener(TextOperationEvent.CHANGE,
handleUserInputChange);
break;
case passwordInput:
passwordInput.addEventListener(TextOperationEvent.CHANGE,
handlePasswordInputChange);
break;
case submitButton:
submitButton.addEventListener(MouseEvent.CLICK,
handleSubmitButtonClick);
}
}
private function handleUserInputChange(event:TextOperationEvent):void {
validateUsername(userInput.text);
}
...
}
What's important here?
The variables marked as SkinPart will automatically be assigned the components with the same id that exist in the Skin you just created. For instance <s:TextInput id="userInput"/> will be injected into public var userInput:SkinnableTextBase;. Note that the type is different: SkinnableTextBase is the base class of TextInput; this allows us to create another skin with e.g. a TextArea instead of a TextInput and it'll work without touching the host component.
partAdded() is called whenever a SkinPart is added to the display list, so that's where we hook up our event listeners. In this example we're validating the username whenever its value changes.
When the validation is done, you can simply set the canSave property to true or false. The binding in the skin on this property will automatically update the Button's enabled property.
And to use both of these classes together:
<v:SignUp skinClass="net.riastar.skin.SignUpSkin"/>
I actually have become quite fond of using RobotLegs.
In my MXML views I try to keep all logic outside of the MXML and simply dispatch events out to the mediator. From there I can put code in the mediator to the heavier AS needed.
Hi, I have been working on a Flex Mobile application using Flash Builder 4.6.
I have 2 mxml 'views' in my project. In one mxml file, i have a function that grabs xml data.
In my other mxml file, I have a refresh button that when depressed is suppsosed to call the function in the first mxml file in order to once again grab the xml data.
I dont know how to call that function from outside the mxml file it is housed in.
I appreciate any help given. Thank you!
[UPDATE #2]*
I thought I should share some more details about my issue.
It is a reddit client mobile app. It fetches the feeds, etc.
In my main view called RedditReaderHomeView.mxml, I am using a splitViewNavigator spark component to house two other views like so:
RedditReaderHomeView.mxml
<s:SplitViewNavigator width="100%" height="100%" id="splitViewNavigator" autoHideFirstViewNavigator="true">
<s:ViewNavigator id="redditList" firstView="views.subredditList" width="300" height="100%"/>
<s:ViewNavigator id="redditFeed" firstView="views.redditFeed" width="100%" height="100%">
<s:actionContent.landscape>
<s:Button id="refreshButtonlLandscape" icon="#Embed('assets/refresh160.png')" click="refreshRSS()" />
</s:actionContent.landscape>
<s:actionContent.portrait>
<s:Button id="refreshButton" icon="#Embed('assets/refresh160.png')" />
<s:Button id="navigatorButton" label="Search" click="splitViewNavigator.showFirstViewNavigatorInPopUp(navigatorButton)" />
</s:actionContent.portrait>
</s:ViewNavigator>
</s:SplitViewNavigator>
As you can see in the code above, in my main view I have a button with the id "refreshButton." When I click this button, I want the reddit data to refresh. In other words I want to call a function to refresh the data, that is housed in the view, 'redditFeed'.
This is the function which is in a separate view named 'redditFeed.mxml', that I want to call using the refresh button in the main view shown above.
redditFeed.mxml
protected function myList_creationCompleteHandler(url:String):void
{
getRedditFeedResult.token = redditFeedGrabber.getRedditFeed(url);
getRedditFeedResult.addEventListener(ResultEvent.RESULT,busyOff);
}
I hope this helped clear out confusion as to what I was trying to do. Im assuming that the solution is quite simple, but alas, I am a novice programmer and new to Flex, so Im learning the ropes. Any help is appreciated. Thank you!
IF you have an instance of the view, then just do:
myViewInstance.myPublicFunction();
In MXML, the id element of the MXML tag is used to reference the view in ActionScript. Since you didnt' describe your architecture; it is unclear how one view can call the other.
If the view that needs to trigger the call is a parent of the view that has the function to make the call, then you could use the approach described above.
If the view that need to trigger the call is a child of the view that has the function to make the call, then you should dispatch an event from the "child" which the parent can listen to. In the event handler you would trigger the call.
If the view that needs to trigger and the view that has the function to make the call are both children of the same parent; then you should dispatch an event from the "Trigger" view, listen for it in the parent, and then use that event listener to make the call (Using similar code to what I explained above).
If you have a more complicated architecture of these two views; then you should look into some method to encapsulate the "remote call" functionality, such as into a service class. Many frameworks offer approaches to share that service class and/or results across multiple classes. ( MXML Files are classes).
There are two ways you can do this without getting into bad architecture by having the child view explicitly know about its parent:
Your child view can generate an event, which the parent is listening for. The parent will then call the function
The child view can have a public property of type Function. The parent view passes a reference to that function by setting the variable. The child view then calls the function (after checking to make sure it is not null).
I hava a problem with flashbuilder:
I have a list with an itemrenderer that renders an image that (should be) draggable.
the rendered image refers to a function that is declared in an actionscript file: dragDrop.as in the folder AS.
the list:
<s:List id="imageList" width="139" height="438"
dataProvider="{xmlListColl}"
itemRenderer="itemRenderer.ImageRenderer"
dragEnabled="true">
</s:List>
the itemrenderer renders this image and refers to the function doDrag:
<mx:Image width="100" height="70" maintainAspectRatio="true"
MouseDownEffect="AS.dragDrop.doDrag(event)"
source="{data.#thumbnailImage}"/>
the function in dragDrop.as:
public function doDrag(event:MouseEvent):void
{
var img:mx.controls.Image = event.currentTarget as mx.controls.Image;
var dragImg:mx.controls.Image = new mx.controls.Image();
dragImg.source = img.source;
var dsource:DragSource = new DragSource();
dsource.addData(img, 'img');
DragManager.doDrag(img, dsource, event, dragImg);
}
but it seems the function is never called...
also parentdocument and outerdocument don't seem to work (if i put the function in the document where the itemrenderer is called)
Please Help!
There's a few issues here, but ultimately, you're not seeing a reference to that method, which means your dragDrop.as file is not including.
Here are a few suggestions:
Replace MouseDownEffect with mouseDown. Instead of causing an effect to occur, you're now listening for the "MouseEvent.MOUSE_DOWN" event to fire. Differences between effects and responding to events are described here and, to quote, "Behaviors let you add animation and motion to your application when some user or programmatic action occurs, where a behavior is a combination of a trigger paired with an effect. A trigger is an action, such as a mouse click on a component ... An effect is a visible or audible change to the target component that occurs over a period of time, measured in milliseconds."
Make sure you're including your dragDrop.as file. Flex 3 vs. Flex 4 handle script tags differently. If you're not including or importing your code, then of course it won't fire.
include vs import is a good question. You can "include" code that's a definition of methods, instances, constants, etc. But you would "import" defined classes for use. Since your method is a public function, does it live within a class? Or is it meant to just live in the script file, in which case you should remove the accessor "public"
If you're looking to implement Drag-and-Drop, I highly recommend NOT re-inventing the wheel and checking out what Adobe has already implemented for components, including dragEnabled='true' and dragMoveEnabled='true'. Check them out here: http://livedocs.adobe.com/flex/3/html/help.html?content=dragdrop_4.html
http://livedocs.adobe.com/flex/3/html/help.html?content=dragdrop_1.html
Here is an example of a Flex 3 script tag:
<mx:Script source="AS/dragDrop.as"/>
Here is an example of a Flex 4 script tag:
<fx:Script source="AS/dragDrop.as"/>
This is an link to the documentation on how to include directly into a <fx:Script> tag the code you'd like: http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf61c8a-7ff4.html
I am working on a small AIR desktop application and I have some configuration infos that I want to store in a little file that's loaded at some point when the application starts and will be used to set public properties on the root application object. This should work just as if I had public variables declared in an <mx:Script> block at the beginning of my main MXML file.
I seem to have the choice of three events that could be used to initiate loading the configuration file:
invoke
initialize
creationComplete
Did I overlook some more? Which one is appropriate and why? Does it matter at all?
Example issues that come to my mind are:
are all components already accessible or will I get NULL references?
will some of my settings be overwritten in a phase that's coming after the event?
There's probably more.
If your handler needs to access UI components directly, you should wait for creationComplete; otherwise you'll get NULL references.
If you simply want to set properties on the root Application object, initialize seems the best place to do this. If you wait until creationComplete, and if the properties that you set are bound to your controls, then you might get a run-time resize or flicker as those components are updated.
I have an application built in Flex Builder 3. It has a fair amount of mxml and as3 code which uses some other custom compenents. I have looked at the documentation on building components which shows how to make a simple mxml or action script component that extends something like a combobox, but I'm lost as to how to take a whole existing and independently functioning Application and turn it into a reusable component.
Basically, I'd just like to create multiple instances of this app inside of another flex project.
Anyone able to provide a little guidance?
The easy thing to do is to swap the Application mxml tag with a VBox tag...thus making it act like a component.
e.g. If this were your application:
//Foo.mxml
<mx:Appliction xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label text = "foo" />
</mx:Appliction>
change it to:
//Foo.mxml
<mx:VBox>
<mx:Label text = "foo" />
</mx:VBox>
and then you can do something like this:
//App.mxml
<mx:Appliction
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:local="your.package.scheme.*"
>
<local:Foo />
</mx:Appliction>
You may have to make some public properties if you need to pass in any data to the component...
If you simply want some "parent" Flex application to embed several instances of this autonomous child application, then you should see Adobe's "Embedding Asset Types" documentation, which describes how to embed one SWF file in another.
From the documentation:
You typically embed a Flex application
when you do not require the embedding
application to interact with the
embedded application. If the embedding
application requires interactivity
with the embedded application, you
might consider implementing it as a
custom component, rather than as a
separate application.
If you do require interaction between the embedded application and the parent application, you can look into the SWFLoader control.