Obtain reference to View in ActionScript class within ViewNavigatorApplication - actionscript-3

I've got a very simple project in FlashBuilder 4.5. It's a mobile application of type ViewNavigatorApplication with a single view, MapView. In the MapView.mxml file, I've got a Flex component of type Map declared in xml.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" name="CatBusMapView">
<fx:Script>
<![CDATA[
import com.esri.ags.Map;
....
]]>
</fx:Script>
<fx:Declarations>
....
</fx:Declarations>
<esri:Map id="cbm">
...
</esri:Map>
</s:View>
In this same project, I've an actionscript class called UserGeolocation. In this class, I'm attempting to get a reference to this map component.
So far, I can get a reference to the top-level application, its ViewNavigator and the NavigationStack of said ViewNavigator. However, I cannot find a way to access the MapView, much less the map I've declared within it.
I'm aware of methods like firstView() and activeView(), but I want an absolute solution, one that retrieves the view regardless of whether or not it's first or active. I've tried navigator.getChildByName("MapView") with no luck.

You could also do it using events. Fire a custom event from the MapView onActivate/creationComplete, and pass the esri map component cbm as the data part of the event.
Have a listener in the main ViewNavigatorApplication class that listens for this event. In the handler of the event listener, you can access this through event.data, and then assign it to a variable declared in the main class or in the UserGeolocation class.
Brian

Just to underscore the original intent of the question: I want an absolute reference to a View in a ViewNavigatorApplication. I'm surprised there's no clear way of doing this in the API, since it seems common practice to put Flex components in Views, in the form of declarative MXML. Existing methods that manipulate the stack aren't helpful in this regard, because they are either a) conditional upon the active or first view, or b) affect the visual presentation of the application.
There are three general solutions that have been suggested which, oddly enough, focus on problems engendered by multiple stacks in TabbedViewNavigatorApplication and don't mention the ViewNavigatorApplication.
Put the object/component you want access to at the top of the container hierarchy (ie FlexGlobals.topLevelApplication)
Use a lightweight framework
Use events (either custom or existing)
I opted for the first.

Related

In Flex, how should properties be passed to child components?

I'm new to Adobe Flex, and am working on a desktop Air application. The jist of my problem is figuring out how a child component can be aware of one of its parents properties. The parent might be more than one level up.
Here's a simplified example to illustrate.
I have a custom component that is made up of a few child components, in the example there is only a single button. I have several instances of this custom component next to each other. When one of the child buttons is pressed, I want to generate an event that lets another part of my application know which instance of the custom component the button belonged to. I understand how to create custom events, so I left that part out of the sample code.
My current approach involves creating a property, (e.g. a "position" integer) that I assign to each of the parent components in mxml. The children components also have the position property, which is set to match the parent when the "preinitialize" event occurs. According to the component lifecyle, the preinitialize event occurs in parent components first, then goes down the line of children. Is this safe? Or is there a better way to do this?
Using data binding seems a waste of resources, because the position property never changes after the application loads.
Here are some relevant code snippets.
main.mxml
<s:VGroup>
<components:CustomComponent position="0"/>
<components:CustomComponent position="1"/>
<components:CustomComponent position="2"/>
</s:VGroup>
CustomComponent.mxml
<fx:Script>
<![CDATA[
[Bindable]
public var position:int;
]]>
</fx:Script>
<components:CustomButton
preinitialize="(event.target as CustomButton).setPosition(position)"/>
CustomButton.mxml
<s:Button>
<fx:Script>
<![CDATA[
public var position:int;
public function setPosition(position:int):void
{
this.position = position;
}
]]>
</fx:Script>
</s:Button>
"how a child component can be aware of one of its parents properties."
-> this.parent.propertyName;
The parent might be more than one level up.
-> Then it is not a parent, but an ancestor. You might need to go up the parent chain. this.parent.parent.
Also look into this.document and this.owner. For list based controls these mean different things.
Finally, Look into event bubbling. Sounds like you want your events to bubble up to your top level container.
Generally, this is where a framework/microarchitecture comes into play. You have to keep in mind, that the Flex/Adobe Air library is first and foremost a component library. That means you don't get anything out of the box to help with things such as communication between different part of the app. Sometimes folks will try to use the Singleton Pattern to manage dependencies, but I can tell you from experience that is a horrible mistake that will cost you in the long run as the code becomes very brittle and fragile with high cyclomatic complexity.
Nowadays, there are many frameworks designed to help you with the problem and others that you have and will face. A list of these frameworks can be found through Google, but Swiz, Mate, Robotlegs and Parsley is a great starting point.
There are other frameworks that you may run across such as Cairngorm and PureMVC. Those are generally termed "first generation" frameworks. Personally, I shy away from those because they feel a little too heavy an intrusive.

When creating custom layouts in Flex, why do you "have to" override updateDisplayList() and measure()?

When creating custom layouts in Flex, you generally override LayoutBase, in which case the documentation and tutorials on the Internet say you "have to" override the functions updateDisplayList() and measure(). . .Huh?
I don't think there is a construct in AS3 to syntactically require a function to be overridden, and there sure isn't one here. There's not even as special logic to raise unhandled Errors or anything. This works perfectly fine:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns="*" backgroundColor="#000000" showStatusBar="false" click="createImage()">
<fx:Script>
<![CDATA[
import spark.components.Image;
[Embed(source="AL.png")]
private static const IMAGE:Class;
private var iX:int = 0;
private var iY:int = 0;
private function createImage():void
{
var img:Image = new Image();
img.source = IMAGE;
img.width = 100;
img.height = 100;
img.x = iX
img.y = iY;
iX += 100;
iY += 100;
grp.addElement(img);
}
]]>
</fx:Script>
<s:Group id="grp" width="400" height="400">
<s:layout>
<GridLayout/>
</s:layout>
</s:Group>
</s:WindowedApplication>
And in my GridLayout.as class:
package
{
import spark.layouts.supportClasses.LayoutBase;
public class GridLayout extends LayoutBase
{
}
}
Each time I click on the application, a new image is spawned at (x, y) * n, where n is the number of images previously spawned. It works perfectly fine. I even added code so that right-clicking would take an already existing image and move it around on the screen, and that worked fine as well.
So I guess my question is. . .Why in the world are they saying this is absolutely required? What do they mean? I can understand the documentation and stuff saying that those two functions are where you want to concentrate your customizations at or something like that, but in programming, saying that a function override is required is some pretty strong language; if stuff holds up just fine without you overriding those functions, why would both documentation and independent tutorials be saying this? Thanks!
Why in the world are they saying this is absolutely required?
Since I don't know what documentation you're reading; it is tough to say. The documentation could be wrong; or you could be taking something out of context. It is not required that you write any sort of code in an updateDisplayList() or measure() method, but...
What do they mean?
In the context of creating Flex components; it makes sense to make use of the Flex Component LifeCycle methods, for either MX components or Spark Components. The lifecycle methods (createChildren(), commitProperties(), updateDisplayList(), and measure() are executed by the Flex Framework and make use of an invalidation cycle built right into the framework.
The framework methods help you put "similar" code in the same place so you don't have it all over the place.
The Spark Framework changed things a bit by providing the option of separating layout and sizing code (AKA updateDisplayList() and measure() out of the main class and into a specific layout class.
saying that a function overload is required is some pretty strong
language
I'd be surprised if you've read any docs that say that overloading is required. Overloading is the act of creating multiple functions with the same name, but different arguments. This is not supported in ActionScript. Overriding is the act of extending a function in a child component in order to change or extend functionality of that function. They are different concepts; and I'm unclear if that was a typo on your part or if you are confused about some tenants of object oriented programming.
Does this help? [Unfortunately, I don't have the time right now to try to re-work your sample to make proper use of Flex Framework conventions.
Why in the world are they saying this is absolutely required?
I understand your concern, these overriding functions are required for the components to works optimally. These components don't require to follow these component lifecycle principles if your applications is small, the component does not change frequently and no body else touches your class.
But, If your app needs to change these components frequently then you might have enforce these lifecycle principles.
For example: you want to Prepare Coke, steps(I'd say life cycle) would be take water > mix sugar > add colors > mix soda > bottle it
Now you get orders to change the color of the Coke that you just prepared, the life cycle is already completed, if you need to change anything at this point, you need to put a lot of effort even to change the color of it. If you had followed the life cycled, it makes life easier for the app at run time. No performance issues.

Dynamic Tree Generation in Flex Actionscript

I am using the URL logic for creating a dynamic Tree in Flex using action script. However the output is not properly shown (Object name is shown instead of Label).
Code is available in above mentioned URL.
Please help.
Write a correct toString() implementation of your DataTreeNode, so it would have a proper display in this tree.
An example: Provided the class DataTreeNode has a data:Object field, and this object has a urlToDisplay:String property that you want displayed. Do like this:
override public function toString():String {
if (!data) return '[null]';
return data.urlToDisplay;
}
If you only rely on simple Objects or data classes, you can use the tree's labelField or labelFunction in order to read and/or format data, which is passed to the renderer. There are no new item renderer classes needed.
New renderer should be compatible with these functions!
On a site note: item renderer are not "mostly just simple MXML classes", they are component instances. It doesn't matter how there are implemented. There are best practises like avoiding data bindings in item renderers, that's why it is common to use the markup for drawing, but implementing the views behaviour according to the Flex component live cycle. you might want to read about it in the documentation, because it is a necessary read for a Flex developer.
You will have to write an ItemRenderer that tells your tree how it should display the components. ItemRenderers are mostly just simple MXML classes that access one item each and display the data in any way you want. You will have to assign the ItemRenderer to your component.
See this article:
http://help.adobe.com/en_US/flex/using/WS03d33b8076db57b9-23c04461124bbeca597-8000.html

How to add MXML components to an ActionScript application?

I'm building an ActionScript 3 project, and have found that writing some components in MXML would simplify things.
It seems like I'd need to extend the Flex Application class in order to do that. If that is right, how should I do that?
Currently my Main object extends Sprite. Other Sprites are then added to it with addChild(), and I'd like Flex components in one of those. Surely there is a way without rewriting my application completely in MXML?
Edit As posted in the comments my explanation here is mostly regarding transitioning to a Spark application, the same kinds of ideas apply going to MX Application except with MX you could stick with addChild, generally speaking there you would need to implement IUIComponent to use containers see docs:
Note: While the child argument to the method is specified as of type
DisplayObject, the argument must implement the IUIComponent interface
to be added as a child of a container. All Flex components implement
this interface.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html#addChild()
End Edit
You can switch your base class to Application instead of Sprite, but when adding elements to a Flex 4 application it expects that they implement IVisualElement. Generally speaking you would switch your addChild calls to addElement, and you would have to change your other classes that currently extend Sprite/MovieClip/DisplayObject to extend something like Group so that they implement the necessary interfaces for Flex Application to work with them (generally it expects more things than lower level Flash objects provide since it has the LayoutManager, PopUpManager, Component Life cycle, etc.). The issue here is you'll be adding some weight to your components, if this is meant for the web or desktop I wouldn't be too concerned but this will affect performance on mobile devices, noticeably.
Unfortunately it's not a turn-key type solution, it requires some manual modification of the code since you have to make the call on what to change each object to based on it's functionality, sometimes Group is the right way to go other times you might get more benefit out of other containers or controls. In some cases you may want to stick with your current lower level extension (say extending Sprite) and just implement IVisualElement yourself.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html#addElement()
If you wanted to wholesale switch to using an MXML file for your application you could also create a basic MXML application file, and have it include a script block with your existing code (modified so constructor code is moved into creation complete). Alternatively you can have a base .as file that extends application then use that as the base class for your MXML, I'll throw together some examples.
Example 1 A very basic MXML Application file
<?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">
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</s:Application>
Example 2 An AS3 Class extending application and an MXML class extending that
[Main.mxml]
<?xml version="1.0" encoding="utf-8"?>
<MyBaseApp
xmlns="*"
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">
<s:Button id="btnControl"/>
</MyBaseApp>
[MyBaseApp.as]
package
{
import mx.events.FlexEvent;
import spark.components.Application;
import spark.components.Button;
public class MyBaseApp extends Application
{
public var btnControl:Button;
public function MyBaseApp()
{
super();
addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
}
private function creationCompleteHandler(event:FlexEvent):void
{
btnControl.label = "something I set in AS3";
}
}
}

learning flex 4 facing problem with namespaces

I am trying to learn flex4 from adobe document and I am very confused while using three namespaces.. there is no way i can keep track of when to use what often ending up using fx inside mx or s or similarly making some stupid goofed up combinations of {fx,mx,s}.
Adobe document is huge and i am looking for some good starting point for learning flex .
Your question is quite large; however, some basic explanation about the 3 namespaces you've cited:
<fx> tags are typically programmatic functionality and not visual display objects. You'd use it for declaring a script block in a MXML document or defining variables in a declarative way.
<fx:Script>
<![CDATA[
[Bindable]
public var myVariable:String = "Hello, World!";
]]>
</fx:Script>
<fx:Declarations>
<fx:Object id="variableName"
property1="myCustomProperty"
property2="anotherCustomProperty" />
</fx:Declarations>
When declaring visual elements and UIComponents on the display list, you'll typically want Spark architecture; therefore, you'd use the Spark namespace.
<s:Group />
MX architecture is important, but is generally deprecated by Spark. If a component is available as Spark, you should use that implementation.
<mx:Box />
All are just packages of the framework, and really no difference than importing packages in ActionScript. Your custom components will use their package name as a namespace, or you declare a namespace for your Flex MXML library.
If you're using an IDE like Flash Builder, you usually don't have to worry about the namespaces.
In an MXML file, enter the start tag (ie: <), skip the namespace and start typing the class you're after. In the above examples, I'd hit <s for "script" and the intellisense will show you completion options that will insert the namespace for you.
If the auto completion options do not appear, hit [ctrl]+[space-bar].
Let Flash Builder help with namespaces by completing them for you.
Probably doesn't go far to helping you out, but hopefully this helps a little.
Have you tried http://www.adobe.com/devnet/flex.html especially Getting Started part?