getting Deep into Flex - actionscript-3

The better you understand what you are doing, the better you will do it.
I want to get Deep into Flex . I did some simple Event-Handling and
The better you understand what you are doing, the better you will do it.
But i have i big question:
What does the Compiler do ?!
What happens with the MXML file ?
lets say we have a simple code ( code from blogflexexamples):
<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/12/27/changing-the-flex-colorpicker-controls-swatch-panel-background-color/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="top"
backgroundColor="white">
<mx:Style>
.myColorPicker {
swatchPanelStyleName: myCustomSwatchPanelStyleName;
}
.myCustomSwatchPanelStyleName {
backgroundColor: haloBlue;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.events.ColorPickerEvent;
private function backgroundColor_change(evt:ColorPickerEvent):void {
var cssObj:CSSStyleDeclaration = StyleManager.getStyleDeclaration(".myCustomSwatchPanelStyleName");
cssObj.setStyle("backgroundColor", evt.color);
colorPicker.open();
}
]]>
</mx:Script>
<mx:ApplicationControlBar dock="true">
<mx:Form styleName="plain">
<mx:FormItem label="backgroundColor:">
<mx:ColorPicker change="backgroundColor_change(event);" />
</mx:FormItem>
</mx:Form>
</mx:ApplicationControlBar>
<mx:ColorPicker id="colorPicker"
styleName="myColorPicker"
editable="false" />
</mx:Application>
does this generate an Actionscript file ?
and if it does : Can i see the the .as file ( like preprocessor in C++ )?

Yes. MXML is translated into an ActionScript class. You can see the generated as code by adding -keep-generated-actionscript switch to the Additional compiler arguments in Project properties->Flex compiler.

Another good reference is the recently-released book Developing Flex 4 Components by Mike Jones. It mentions the compilation of MXML to Actionscript on page 4 and provides a solid grounding in how Flex components work.

For reference, here are some good places to digg deep into the Flex Compiler:
Diving in the Data Binding Waters (with Presentation Slides) - Shows how [Bindable] is converted into actionscript
Flex SDK Compiler Source Code
Flex 3 Compiler Design
Flex Mojos (with Source SVN) - Awesome code customizing how the compiler processes things.
Clement Wong's Blog - He was the previous leading Flex Compiler Engineer, points to some good resources.
Customizing Metadata Processing with Flex 4 Custom Compiler Extensions - New resources for the Compiler

Related

Passing data between MXML files and opening one after Click on another

I am pretty new to flex and was trying to understand how the entire Flex works
Scenario :
I started with creating a single MXML file where there will be a textbox and a button. If the button is clicked a popup will be displayed with the value of the textbox(this worked perfectly). The second thing that came to my mind is how to show the same data in some other page. SO, if i click on the button. It should load another page and display the data that was written in the textbox
My Code till now is this :
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
public function open(event:MouseEvent):void{
Alert.show("I am opening a page");
Alert.show(txt_inp.text + " is written here");
}
]]>
</mx:Script>
<mx:TextInput id="txt_inp" />
<mx:Button id="openBttn" label="Click Me" click="open(event)" />
</mx:Application>
And Name.xml(The Second page is )
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="setYelp()">
<mx:Script>
<![CDATA[
public var helloYou:HelloYou;
public function yelpHandler():void{
yelp.text = "Ayush"
}
public function setYelp():void {
helloYou.openBttn.addEventListener(MouseEvent.CLICK,yelpHandler);
}
]]>
</mx:Script>
<mx:Label id="yelp" text="yelp">
</mx:Label>
</mx:Application>
I referred to some of the previously asked questions like this and tried following it, but couldn't really understand.
Also, in my flex builder I had two more options of MXML > MXML Module and MXML Component. Should I use them here, if not, when should I use it?
Why are you using multiple page? usually a Flex application is a single application with multiple views and sharing data is way easier in this situation.
If you want to pass information between different pages you can use cookies (see for example Accessing browser cookies from Flex)
Another flex solution is this http://custardbelly.com/blog/blog-posts/2010/11/15/flex-hero-persistant-data-in-mobileapplication/
The last thing that I can think about is using the javascript bridge to access the localstorage (o sqlite) of your browser and store information there.
But again why save information between requests and not simply create a single application that changes its views ?
1st solution
Use ViewStack component to integrate your 1st mxml and 2nd mxml.
This is what #wezzy said "single application with multiple views".
This is the most easily way to share values, if you can integrate to one mxml.
like this
<mx:ViewStack id="viewstack" width="100%" height="100%" selectedIndex="0" >
<!-- Input Page is here -->
<mx:Canvas id="view1" width="100%" height="100%">
<mx:TextInput id="txtName" width="150" maxChars="40" />
<mx:Button label="Go to NextPage" click="viewstack.selectedChild=view2;"/>
</mx:Canvas>
<!-- Result Page -->
<mx:Canvas id="view2" width="100%" height="100%">
<mx:TextInput text="{txtName.text}" width="150" editable="false" />
<mx:Button label="Back to PrevPage" click="viewstack.selectedChild=view1;"/>
</mx:Canvas>
</mx:ViewStack>
2nd solution
Use SharedObject(or DB) to save and load values.
3rd solution
Use singleton variables to share the values between classes.
Please see this answer of mine.
Flex - Problems in accessing static variable on another mxml page

Flex mx:SWFLoader Loads Incorrect SWF File

I'm fairly new to Flex and am having an issue where I have a main Flex program (let's called it "Parent.swf") attempting to load another Flex application (Child.swf) via the SWFLoader class/component.
Environment is Flex 4.6 on FlashDevelop.
The call appears to work correctly (i.e. no IO or sandbox errors are returned), only that it seems to reload the "Parent.swf" into the SWFLoader instead of the "Child.swf".
For example, I have the Parent.swf containing:
<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"
initialize="doStartup()"
width="1024" height="768">
...
<fx:Script>
<![CDATA[
private function doStartup():void
{
trace("STARTING UP!");
}
....
]]>
</fx:Script>
<mx:VBox top="10" left="10" width="100%" horizontalAlign="center">
<mx:Label text="I'M A LOADER!" />
</mx:VBox>
<mx:VBox top="10" left="10" width="100%" horizontalAlign="center">
<mx:SWFLoader
id="pluginLoader"
source="plugins/Child.swf"
autoLoad="true"
height="400" width="400"
complete="onPluginLoaded(event);"
ioError="onPluginLoadError(event);"
securityError="onPluginSecurityError(event);"
httpStatus="onHttpStatus(event);"
init="onInit(event);"
open="onOpen(event);"
progress="onProgress(event);"
unload="onUnload(event);"
/>
</mx:VBox>
....
The child swf contains:
....
<mx:Label text="I'M A PLUGIN!" />
....
The trace above (i.e. "STARTING UP!") is repeated on the load of Child.swf, followed by another attempt to load Child.swf which fails because the working directory for the call is now in the "plugins" directory.
So it seems to know the file exists and load it, but somehow swaps in Parent.swf over the top of it.
Note that if I execute Child.swf directly, I'm able to verify that it is what I expect it to be (i.e. a flex app with a single label saying "I'M A PLUGIN!").
I've also tried various other approaches such as instantiating a SWFLoader via code but the same issue occurs. I even tried to switch to Modules but had the same behaviour there too.
It fails whether run locally or run via a web server.
Does anyone have any idea how this could occur? Is there some way that the main.mxml of Parent.swf is overriding Child.swf?
(Sorry for the essay)
I need the full code to discovery. But I can suggest two ideas:
Check your onPluginLoaded function, it can be called by Parent instead of the Child
Check if you don't have any class or object name repeated that can generated a cross-reference. For example, both Parent and Child use MyScrollbarClass. As this class was firstly loaded by Parent, it will create a new name when load in Child, like MyScrollbarClass_1
mxml file must be named differently in loaded applications

How do I get autocompletion for Flex Metadata?

I took a look at flex metadata and it seems to be quiet straight forward. Though I have a problem, I don't get autocompletion for the metadata.
I'll tell you what I did, maybe you find an error. I want to create my own Style metadata tag named e.g. MyStyle. I want to create my own because it's easier for me to determine at runtime if the metadata was added by me or by the flex framework (therefore I will not use the predefined Style metadata tag).
To add metadata is pretty simple, I just wrote this code to get it work:
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
width="1024" height="768">
<fx:Metadata>
[MyStyle(required="true")]
</fx:Metadata>
</s:Group>
On my WindowedApplication component I added an added to stage listener to the stage. So all elements that are added to the application will fire that Event.ADDED when they are added to the stage. In that eventHandler I scan added elements for my metadata tag.
protected function addedToStageListener(event:Event):void
{
var classInfo:XML = describeType(event.target);
for each (var x:XML in classInfo..metadata)
{
if (x.#name == "MyStyle")
trace(x);
}
}
I also added a flex-config.xml file (in the toplevel of my src folder) to add the compiler options, so that I can read my custom metadata tag on runtime. The file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<flex-config>
<compiler>
<keep-as3-metadata>
<name>MyStyle</name>
</keep-as3-metadata>
</compiler>
</flex-config>
When I run this, I get the result I expect
<metadata name="MyStyle">
<arg key="required" value="true"/>
</metadata>
So this works. My next step was to add autocompletion when adding the metadata tag to the code. To do this you should create a metadata.xml which specifies the metadata tags right?
So I did this and I ended up with this simple metadata.xml
<?xml version="1.0" encoding="UTF-8"?>
<annotations version="2.1.1">
<metadata name="MyStyle" description="Adds style.">
<context name="class" />
<attribute name="required" type="Boolean" required="true" />
</metadata>
</annotations>
To add the metadata.xml correctly to the project I followed that tutorial by Adobe, but it doesn't work. I don't get autocompletion. Do you have any suggestions?
Update: I use Flash Builder 4.6 Professional and I created a Flex Library Project.

What is the hostComponent?

Im skinning a progressBar in Flex, and after reading a bit about it, I see that there is something called hostComponent.
Adobe site says:
"The host component is the component that uses the skin. By specifying the host component, Spark skins can gain a reference to the component instance that uses the skin by using the hostComponent property."
But, I still dont understand how this exactly works.
Any quick and practical explanation?
Thanks!
When you create custom components in the Spark architecture, you usually split them up into two parts:
an ActionScript class that contains the core functionality of the custom component. This class will usually extend SkinnableComponent or SkinnableContainer
an MXML skin class which is loosely associated with that ActionScript class and contains only the visual presentation of the component. This class should contain no real functionality and it should be trivial to substitute it with another skin.
The first of these two classes is referred to as the host component from the skin's point of view.
A simple example
Let's create a very simple panel by extending SkinnableContainer:
public class MyPanel extends SkinnableContainer {
[Bindable]
public var title:String;
}
As you can see, I made a property 'title' which we want to use to display a title in the Panel. Now let's create a skin that uses this property:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("path.to.MyPanel")]
</fx:Metadata>
<!-- graphics for title bar go here -->
<s:Label text="{hostComponent.title}" top="5" left="5" />
<!-- graphics for panel content go here -->
<s:Group id="contentGroup" top="30" bottom="0" left="0" right="0" />
</s:Skin>
The hostcomponent is defined in the 'metadata' block and you see that we can use it to bind its properties into our visual representation. The 'contentGroup' is there because it is required by SkinnableContainer; this is were all the elements will go that you put inside the custom panel. So here's how to use it:
<myComps:MyPanel title="Panel title" skinClass="path.to.skins.MyPanelSkin">
<s:Label text="Hello Panel" />
<!--everything in here goes into the 'contentGroup'-->
</myComps:MyPanel>

Flex - ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller when using added swc file

I know already so many questions have been asked here on this error #2025 topic.
But, in my case, it is happening when trying to use a .swc file in a flex project.
I am trying to use one of my library project into another flex project by adding using "Add swc" file.
I have successfully added it in my new project as a .swc file.
But, when I try to use it new project by clicking on the application in browser, it shows me this runtime error. Below is my new project's main file.
NewSample.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:swclib="*"
layout="absolute">
<swclib:Main width="100%" height="100%"/>
</mx:Application>
StackTrace:
ArgumentError: Error #2025: The supplied DisplayObject must be a child
of the caller. at
flash.display::DisplayObjectContainer/getChildIndex() at
mx.managers::SystemManager/getChildIndex()[C:\autobuild\3.x\frameworks\projects\framework\src\mx\managers\SystemManager.as:1772]
at
mx.managers::SystemManager/mouseDownHandler()[C:\autobuild\3.x\frameworks\projects\framework\src\mx\managers\SystemManager.as:3615]
I am unable to identify what caused the error ?
EDIT : This is the main application file of the .swc library file.
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:parsley="http://www.spicefactory.org/parsley"
minWidth="955" minHeight="600"
xmlns:custom="components.*"
horizontalScrollPolicy="off"
layout="vertical"
verticalScrollPolicy="off" xmlns:models="models.*" xmlns:views="views.*">
<views:Header width="100%" height="50"/>
<mx:HDividedBox id="hdv" width="100%" height="100%">
<views:ABC width="15%" height="100%"/>
<views:DEF width="65%" height="100%"/>
<views:XYZ width="20%" height="100%"/>
</mx:HDividedBox>
<parsley:ContextBuilder config="Conf"/>
</mx:Application>
Do you really need Application? Application should be only the upper one and main class.
Possible solutions:
Use another container (for example Canvas).
Compile your Main.mxml application into swf and then load it with Loader class.
I'd prefer to use 1st variant.
I bet you are not checking if the (you think child) object is actually a child of the (you think parent) object
Put an if there like:
if(parentObj.getChildren().indexOf(childObj) >= 0) {
parentObj.removeChild(childObj);
} else {
//whatever error logging you do goes here
}