Flex developers can use ActionScript to extend the functionality of their applications. ActionScript provides flow control and object manipulation features that are not available in MXML. For a complete introduction to ActionScript and a reference for using the language, see ActionScript 3.0 Developer's Guide and ActionScript 3.0 Reference for Apache Flex.
Flex developers can use ActionScript to implement custom behavior within their applications. You first use MXML tags to declare things like the containers, controls, effects, formatters, validators, and web services that your application requires, and to lay out its user interface. Each of these components provides the standard behavior you'd expect. For example, a button automatically highlights when you roll over it, without requiring you to write any ActionScript. But a declarative language like MXML is not appropriate for coding what you want to happen when the user clicks a button. For that, you need to use a procedural language like ActionScript, which offers executable methods, various types of storage variables, and flow control such as conditionals and loops. In a general sense, MXML implements the static aspects of your application, and ActionScript implements its dynamic aspects.
ActionScript is an object-oriented procedural programming language, based on the ECMAScript (ECMA-262) edition 4 draft language specification. You can use a variety of methods to mix ActionScript and MXML, including the following:
Define event listeners inside MXML event attributes.
Add script blocks using the <fx:Script> tag.
Include external ActionScript files.
Import ActionScript classes.
Create ActionScript components.
Although a simple application can be written in a single MXML or ActionScript (AS) file, most applications will be broken into multiple files. For example, it is common to move the <fx:Script> and <fx:Style> blocks into separate AS and CSS files that the application then includes.
It is also common for an application to import custom MXML and ActionScript components. These must be defined in other files, and MXML components may put their own <fx:Script> blocks into yet more AS files that they include. Components may also be imported from precompiled SWC files rather than source code. Finally, SWF files containing executable code can also be embedded in an application. The end result of all these input files is a single SWF file.
The Flex compiler transforms the main MXML file and other files it includes into a single ActionScript class. As a result, you cannot define classes or use statements outside of functions in the MXML files and the included ActionScript files.
You can reference imported ActionScript classes from your MXML application files, and those classes are added to the final SWF file. When the transformation to an ActionScript file is complete, Flex links all the ActionScript components and includes those classes in the final SWF file.
When you write an MXML file and compile it, the Flex compiler creates a class and generates ActionScript that the class uses. MXML tags and ActionScript are used by the resulting class in several ways. This information is useful for understanding what is happening in the background of the application.
An MXML application (a file that starts with the <s:Application> tag) defines a subclass of the Spark Application class. Similarly, an MXML component (a file that starts with some other component's tag, such as <s:Button>) defines a subclass of that component.
The name of the subclass is the name of the file. The base class is the class of the top-level tag. An MXML application actually defines the following:
class MyApp extends Application
If MyButton.mxml starts with <s:Button>, you are actually defining the following:
class MyButton extends Button
The variable and function declarations in an <fx:Script> block define properties and methods of the subclass.
Setting an id property on a component instance within a class results in a public variable being autogenerated in the subclass that contains a reference to that component instance. For example, if the <s:Button id="myButton"/> tag is nested deeply inside several containers, you can still refer to it as myButton.
Event attributes become the bodies of autogenerated event listener methods in the subclass. For example:
<s:Button id="myButton" click="foo = 1; doSomething()">
becomes
private function __myButton_click(event:MouseEvent):void {
foo = 1;
doSomething()
}
The event attributes become method bodies, so they can access the other properties and methods of the subclass.
All the ActionScript anywhere in an MXML file, whether in its <fx:Script> block or inside tags, executes with the this keyword referring to an instance of the subclass.
The public properties and methods of the class are accessible by ActionScript code in other components, as long as that code "dots down" (for example, myCheckoutAccordion.myAddressForm.firstNameTextInput.text) or reaches up using the parentDocument, parentApplication, or FlexGlobals.topLevelApplication properties to specify which component the property or method exists on.
One way to use ActionScript code in an application is to include it within the MXML tag's event handler, as the following example shows:
<?xml version="1.0"?>
<!-- usingas/HelloWorldAS.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:BasicLayout/>
</s:layout>
<s:Panel title="My Application" height="128" x="226" y="24">
<s:TextArea id="textarea1" width="155" x="0" y="0"/>
<s:Button label="Click Me"
click="textarea1.text='Hello World';"
width="92"
x="31.5" y="56"/>
</s:Panel>
</s:Application>
In this example, you include ActionScript code for the body of the click event handler of the Button control. The MXML compiler takes the attribute click=" ... " and generates the following event handler method:
public function __myButton_click(event:MouseEvent):void {
textarea1.text='Hello World';
}
When the user clicks the button, this code sets the value of the TextArea control's text property to the String "Hello World." In most cases, you do not need to look at the generated code, but it is useful to understand what happens when you write an inline event handler.
To see the generated code, set the value of the keep-generated-actionscript compiler option to true. The compiler then stores the *.as helper file in the /generated directory, which is a subdirectory of the location of the SWF file.
For more information about events, see Events. For more information on using the command-line compilers, see Flex compilers.
You use the <fx:Script> tag to insert an ActionScript block in an MXML file. ActionScript blocks can contain ActionScript functions and variable declarations used in MXML applications. Code inside <fx:Script> tags can also declare constants (with the const statement) and namespaces (with namespace), include ActionScript files (with include), import declarations (with import), and use namespaces (with use namespace).
The <fx:Script> tag must be a child of the <s:Application> or other top-level component tag.
Statements and expressions are allowed only if they are wrapped in a function. In addition, you cannot define new classes or interfaces in <fx:Script> blocks. Instead, you must place new classes or interfaces in separate AS files and import them.
All ActionScript in the block is added to the enclosing file's class when Flex compiles the application. The following example declares a variable and sets the value of that variable inside a function:
<?xml version="1.0"?>
<!-- usingas/StatementSyntax.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="doSomething()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public var s:Boolean;
public function doSomething():void {
// The following statements must be inside a function.
s = label1.visible;
label1.text = "label1.visible = " + String(s);
}
]]>
</fx:Script>
<s:Label id="label1"/>
</s:Application>
Most ActionScript statements must be inside functions in an <fx:Script> block. However, the following statements can be outside functions:
import
var
include
const
namespace
use namespace
When using an <fx:Script> block, you should wrap the contents in a CDATA construct. This prevents the compiler from interpreting the contents of the script block as XML, and allows the ActionScript to be properly generated. It's best to write all your <fx:Script> open and close tags as the following example shows:
<fx:Script> <![CDATA[ ... ]]> </fx:Script>
Flex does not parse text in a CDATA construct, which means that you can use XML-parsed characters such as angle brackets (< and >) and ampersand (&). For example, the following script that includes a greater-than (>) comparison must be in a CDATA construct:
<?xml version="1.0"?>
<!-- usingas/UsingCDATA.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="doSomething()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public var m:Number;
public var n:Number;
public function doSomething():void {
n = 40;
m = 42;
label1.text = "40 < 42 = " + String(n < m);
}
]]>
</fx:Script>
<s:Label id="label1"/>
</s:Application>
The ActionScript 3.0 programming language can be used from within several development environments, including Adobe® Flash® Professional .
The ActionScript API reference is included as part of the ActionScript 3.0 Reference for Apache Flex.
The primary use of ActionScript in your applications is probably going to be for working with the visual cont
rols and containers in your application. Flex provides several techniques for doing this, including referencing a Flex control in ActionScript and manipulating properties during the instantiation of controls and containers.
To work with a component in ActionScript, you usually define an id property for that component in the MXML tag. For example, the following code sets the id property of the Button control to the String "myButton":
<s:Button id="myButton" label="Click Me"/>
This property is optional if you do not want to access the component with ActionScript.
This code causes the MXML compiler to autogenerate a public variable named myButton that contains a reference to that Button instance. This autogenerated variable lets you access the component instance in ActionScript. You can explicitly refer to the Button control's instance with its id instance reference in any ActionScript class or script block. By referring to a component's instance, you can modify its properties and call its methods.
For example, the following ActionScript block changes the value of the Button control's label property when the user clicks the button:
<?xml version="1.0"?>
<!-- usingas/ButtonExample.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private function setLabel():void {
if (myButton.label=="Click Me") {
myButton.label = "Clicked";
} else {
myButton.label = "Click Me";
}
}
]]>
</fx:Script>
<s:Button id="myButton" label="Click Me" click="setLabel();"/>
</s:Application>
The IDs for all tags in an MXML component, no matter how deeply nested they are, generate public variables of the component being defined. As a result, all id properties must be unique within a document. This also means that if you specified an ID for a component instance, you can access that component from anywhere in the application: from functions, external class files, imported ActionScript files, or inline scripts.
You can refer to a component if it does not have an id property by using methods of the component's Spark container, such as the getElementAt() method. For MX containers, you can use the getChildAt() method.
You can refer to the current enclosing document or current object using the this keyword.
You can also get a reference to a component when you have a String that matches the name. To access an object on the application, you use the this keyword, followed by square brackets, with the String inside the square brackets. The result is a reference to the objects whose name matches the String.
The following example changes style properties on each Button control using a compound String to get a reference to the object:
<?xml version="1.0"?>
<!-- usingas/FlexComponents.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script><![CDATA[
private var newFontStyle:String;
private var newFontSize:int;
public function changeLabel(s:String):void {
s = "myButton" + s;
if (this[s].getStyle("fontStyle")=="normal") {
newFontStyle = "italic";
newFontSize = 18;
} else {
newFontStyle = "normal";
newFontSize = 10;
}
this[s].setStyle("fontStyle",newFontStyle);
this[s].setStyle("fontSize",newFontSize);
}
]]>
</fx:Script>
<s:Button id="myButton1"
click="changeLabel('2')"
label="Change Other Button's Styles"/>
<s:Button id="myButton2"
click="changeLabel('1')"
label="Change Other Button's Styles"/>
</s:Application>
This technique is especially useful if you use a Repeater control or when you create objects in ActionScript and do not necessarily know the names of the objects you want to refer to prior to run time. However, when you instantiate an object in ActionScript, to add that object to the properties array, you must declare the variable as public and declare it in the class's scope, not inside a function.
The following example uses ActionScript to declare two Label controls in the application scope. During initialization, the labels are instantiated and their text properties are set. The example then gets a reference to the Label controls by appending the passed-in variable to the String when the user clicks the Button controls.
<?xml version="1.0"?>
<!-- usingas/ASLabels.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initLabels()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.Label;
public var label1:Label;
public var label2:Label;
// Objects must be declared in the application scope. Adds the names to
// the application's properties array.
public function initLabels():void {
label1 = new Label();
label1.text = "Change Me";
label2 = new Label();
label2.text = "Change Me";
addElement(label1);
addElement(label2);
}
public function changeLabel(s:String):void {
// Create a String that matches the name of the Label control.
s = "label" + s;
// Get a reference to the label control using the
// application's properties array.
this[s].text = "Changed";
}
]]>
</fx:Script>
<s:Button id="b1" click="changeLabel('2')" label="Change Other Label"/>
<s:Button id="b2" click="changeLabel('1')" label="Change Other Label"/>
</s:Application>
You can invoke the public methods of a component instance in your application by using the following dot-notation syntax:
componentInstance.method([parameters]);
The following example invokes the adjustThumb() method when the user clicks the button, which invokes the public setThumbValueAt() method of the HSlider control:
<?xml version="1.0"?>
<!-- usingas/ComponentMethods.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public function adjustThumb(s:HSlider):void {
var randomNumber:int = (Math.floor(Math.random() * 10));
s.setThumbValueAt(0, randomNumber);
}
]]>
</fx:Script>
<mx:HSlider id="slider1" tickInterval="1"
labels="[1,2,3,4,5,6,7,8,9,10]" width="282"/>
<s:Button id="myButton"
label="Change Thumb Position"
click="adjustThumb(slider1);"/>
</s:Application>
To invoke a method from a child document (such as a custom MXML component), you can use the parentApplication, parentDocument, or FlexGlobals.topLevelApplication properties. For more information, see Application containers.
You can use ActionScript to programmatically create visual components using the new operator, in the same way that you create instances of any ActionScript class. The created component has default values for its properties, but it does not yet have a parent or any children (including any kind of internal DisplayObjects), and it is not yet on the display list in Flash Player or Adobe® AIR™, so you can't see it. After creating the component, you should use standard assignment statements to set any properties whose default values aren't appropriate.
Finally, you must add the new component to a container, by using the Spark container's addElement() or addElementAt() methods, so that it becomes part of the visual hierarchy of an application. (For MX containers, you can use the addChild() or addChildAt() methods.) The first time that it is added to a container, a component's children are created. Children are created late in the component's life cycle so that you can set properties that can affect children as they are created.
When creating visual controls, you must import the appropriate package. In most cases, this is the mx.controls package, although you should check the ActionScript 3.0 Reference for Apache Flex.
The following example creates a Button control inside the HGroup container:
<?xml version="1.0"?>
<!-- usingas/ASVisualComponent.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import spark.components.Button;
public var button2:Button;
public function createObject():void {
button2 = new Button();
button2.label = "Click Me";
hb1.addElement(button2);
}
]]>
</fx:Script>
<s:HGroup id="hb1">
<s:Button label="Create Object" click="createObject()"/>
</s:HGroup>
</s:Application>
Flex creates the new child as the last child in the container. If you do not want the new child to be the last in the Spark container, use the addElementAt() method to change the order. You can use the setItemIndex() method after the call to the addElement() method, but this is less efficient. For MX containers, you use the addChildAt(), setChildIndex(), and addChild() methods.
You should declare an instance variable for each dynamically created component and store a reference to the newly created component in it, just as the MXML compiler does when you set an id property for a component instance tag. You can then access your dynamically created components in the same way as those declaratively created in MXML.
To programmatically remove a control in Spark containers, you can use the removeElement(), removeElementAt(), and removeAllElements() methods. For MX containers, you use the removeChild() or removeChildAt() methods. You can also use the removeAllChildren() method to remove all child controls from a container.
Calling the "remove" methods does not actually delete the objects from memory. If you do not have any other references to the child, Flash Player includes the object in garbage collection at some future point. But if you have a reference to that child, the child is not garbage collected.
In some cases, you declaratively define a component with an MXML tag. You can set the creationPolicy property of the component's container to none to defer the creation of the controls inside that container. You can then create the component programmatically rather than declaratively. For information on using the creationPolicy property, see Improving startup performance.
The only component you can pass to the addElement() method is a class that implements the IVisualElement interface. In other words, if you create a new object that is not a subclass of mx.core.IVisualElement, you must wrap it in a class that implments IVisualElement before you can attach it to a container. The following example creates a new Sprite object, which is not a subclass of IVisualElement, and adds it as a child of the UIComponent (which implements IVisualElement) before adding it to the Panel container:
<?xml version="1.0"?>
<!-- usingas/AddingChildrenAsUIComponents.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.display.Sprite;
import mx.core.UIComponent;
private var xLoc:int = 20;
private var yLoc:int = 20;
private var circleColor:Number = 0xFFCC00;
private function addChildToPanel():void {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(circleColor);
circle.graphics.drawCircle(xLoc, yLoc, 15);
var c:UIComponent = new UIComponent();
c.addChild(circle);
panel1.addElement(c);
xLoc = xLoc + 5;
yLoc = yLoc + 1;
circleColor = circleColor + 20;
}
]]>
</fx:Script>
<s:Panel id="panel1" height="250" width="300"/>
<s:Button id="myButton" label="Click Me" click="addChildToPanel();"/>
</s:Application>
Scoping in ActionScript is largely a description of what the this keyword refers to at a particular point. In your application's core MXML file, you can access the Application object by using the this keyword. In a file defining an MXML component, this is a reference to the current instance of that component.
In an ActionScript class file, the this keyword refers to the instance of that class. In the following example, the this keyword refers to an instance of myClass. Because this is implicit, you do not have to include it, but it is shown here to illustrate its meaning.
class myClass {
var _x:Number = 3;
function get x():Number {
return this._x;
}
function set x(y:Number):void {
if (y > 0) {
this._x = y;
} else {
this._x = 0;
}
}
}
However, in custom ActionScript and MXML components or external ActionScript class files, Flex executes in the context of those objects and classes, and the this keyword refers to the current scope and not the Application object scope.
Flex includes a FlexGlobals.topLevelApplication property that you can use to access the root application. In some cases, you can also use the parentDocument property to access the next level up in the document chain of an application, or the parentApplication property to access the next level up in the application chain when one Application object loads another Application object.
You cannot use these properties to access the root application if the loaded application was loaded into a separate ApplicationDomain or SecurityDomain, as is the case with sandboxed and multi-versioned applications. For more information, see Accessing the main application from sub-applications.
If you write ActionScript in a component's event listener, the scope is not the component but rather the application. For example, the following code changes the label of the Button control to "Clicked" once the Button control is pressed:
<?xml version="1.0"?>
<!-- usingas/ButtonScope.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:BasicLayout/>
</s:layout>
<s:Panel width="250" height="100" x="65" y="24">
<s:Button id="myButton"
label="Click Me"
click="myButton.label='Clicked'"
x="79.5" y="20"/>
</s:Panel>
<s:Button label="Reset"
x="158" y="149"
click="myButton.label='Click Me'"/>
</s:Application>
Contrast the previous example with the following code:
<?xml version="1.0"?>
<!-- usingas/AppScope.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<!-- The following throws a compiler error because the app level scope does
not have a label to set. -->
<!-- <s:Button id="myButton" label="Click Me" click="{this.label='Clicked'}"/> -->
<!-- <s:Button label="Reset" click="myButton.label='Click Me'"/> -->
</s:Application>
This code does not work because when an event listener executes, the this keyword does not refer to the Button instance; the this keyword refers to the Application or other top-level component instance. The second example attempts to set the label property of the Application object, not the label property of the Button.
Variables declared within a function are locally scoped to that function. These variables can share the same name as variables in outer scopes, and they do not affect the outer-scoped variable. If a variable is just used temporarily by a single method, make it a local variable of that method rather than an instance variable. Use instance variables only for storing the state of an instance, because each instance variable will take up memory for the entire lifetime of the instance. You can refer to the outer-scoped variable with the this. prefix.
To make your MXML code more readable, you can reference ActionScript files in your <fx:Script> tags, rather than insert large blocks of script. You can either include or import ActionScript files.
There is a distinct difference between including and importing code in ActionScript. Including copies lines of code from one file into another, as if they had been pasted at the position of the include statement. Importing adds a reference to a class file or package so that you can access objects and properties defined by external classes. Files that you import must be found in the source path. Files that you include must be located relative to the file that uses the include statement, or you must use an absolute path.
You use the include statement or the <fx:Script source="filename"> tag to add ActionScript code to your applications.
You use import statements in an <fx:Script> block to define the locations of ActionScript classes and packages that your applications might use.
To include ActionScript code, you reference an external ActionScript file in your <fx:Script> tags. At compile time, the compiler copies the entire contents of the file into your MXML application, as if you had actually typed it. As with ActionScript in an <fx:Script> block, ActionScript statements can only be inside functions. Included files can also declare constants and namespaces, include other ActionScript files, import declarations, and use namespaces. You cannot define classes in included files.
Variables and functions defined in an included ActionScript file are available to any component in the MXML file. An included ActionScript file is not the same as an imported ActionScript class. Flex provides access to the included file's variables and functions, but does not add a new class, because the MXML file itself is a class.
Included ActionScript files do not need to be in the same directory as the MXML file. However, you should organize your ActionScript files in a logical directory structure.
There are two ways to include an external ActionScript file in your application:
The source attribute of the <fx:Script> tag. This is the preferred method for including external ActionScript class files.
The include statement inside <fx:Script> blocks.
You use the source attribute of the <fx:Script> tag to include external ActionScript files in your applications. This provides a way to make your MXML files less cluttered and promotes code reuse across different applications.
Do not give the script file the same name as the application file. This causes a compiler error.
The following example shows the contents of the IncludedFile.as file:
// usingas/includes/IncludedFile.as
public function computeSum(a:Number, b:Number):Number {
return a + b;
}
The following example uses the <fx:Script> tag to include the contents of the IncludedFile.as file. This file is located in the /includes subdirectory.
<?xml version="1.0"?>
<!-- usingas/SourceInclude.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script source="includes/IncludedFile.as"/>
<s:TextInput id="ta1st" text="3" width="40" x="170" y="24" textAlign="right"/>
<s:TextInput id="ta2nd" text="3" width="40" x="170" y="52" textAlign="right"/>
<s:TextArea id="taMain" height="25" width="78" x="132" y="82" textAlign="right"/>
<s:Button id="b1" label="Compute Sum"
click="taMain.text=String(computeSum(Number(ta1st.text), Number(ta2nd.text)));"
x="105" y="115"/>
<s:Label x="148" y="52" text="+" fontWeight="bold" fontSize="17" width="23"/>
</s:Application>
The source attribute of the <fx:Script> tag supports both relative and absolute paths. For more information, see Referring to external files that have been included.
You cannot use the source attribute of an <fx:Script> tag and wrap ActionScript code inside that same <fx:Script> tag. To include a file and write ActionScript in the MXML file, use two <fx:Script> tags.
The include directive is an ActionScript statement that copies the contents of the specified file into your MXML file. The include directive uses the following syntax:
include "file_name";
The following example includes the myfunctions.as file:
<?xml version="1.0"?>
<!-- usingas/IncludeASFile.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
/* The myfunctions.as file defines two methods that
return Strings. */
include "includes/myfunctions.as";
]]>
</fx:Script>
<s:Button id="myButton"
label="Call Methods in Included File"
click="ta1.text=doSomething();ta1.text+=doSomethingElse()"/>
<s:TextArea width="268" id="ta1"/>
<s:Button label="Clear" click="ta1.text=''"/>
</s:Application>
You can specify only a single file for each include directive, but you can use any number of include directives. You can nest include directives; files with include directives can include files that have include directives.
The include directive supports only relative paths. For more information, see Referring to external files that have been included.
You can use the include only where multiple statements are allowed. For example, the following is not allowed:
if (expr) include "foo.as"; // First statement is guarded by IF, but rest are not. ...
The following is allowed:
if (expr) {
include "foo.as"; // All statements inside { } are guarded by IF.
}
The use of curly braces ({ }) allows multiple statements because you can add multiple statements inside the braces.
It's best that you not use the include directive if you use a large number of included ActionScript files. You should try to break the code into separate class files where appropriate and store them in logical package structures.
The source attribute of the <fx:Script> tag and the include directive refer to files in different ways.
The following are the valid paths to external files that are referenced in an <fx:Script> tag's source attribute:
Absolute URLs, such as http://www.macromedia.com or file:///C|/site_flashteam/foo.gif.
Relative URLs, such as ../myscript.as. A relative URL that does not start with a slash is resolved relative to the file that uses it. If the tag <fx:Script source="../IncludedFile.as"> is included in "mysite/myfiles/myapp.mxml," the system searches for "mysite/IncludedFile.as".
For an ActionScript include directive, you can reference only relative URLs.
Flex searches the source path for imported classes and packages. Flex does not search the source path for files that are included using the include directive or the source attribute of the <fx:Script> tag.
If you create many utility classes or include multiple ActionScript files to access commonly used functions, you might want to store them in a set of classes in their own package. You can import ActionScript classes and packages using the import statement. By doing this, you do not have to explicitly enter the fully qualified class names when accessing classes within ActionScript.
The following example imports the MyClass class in the MyPackage.Util package:
<?xml version="1.0"?>
<!-- usingas/AccessingPackagedClasses.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import MyPackage.Util.MyClass;
private var mc:MyClass = new MyClass;
]]>
</fx:Script>
<s:Button id="myButton" label="Click Me" click="myButton.label=mc.returnAString()"/>
</s:Application>
In your ActionScript code, instead of referring to the class with its fully qualified package name (MyPackage.Util.MyClass), you refer to it as MyClass.
You can also use the wildcard character (*) to import the entire package. For example, the following statement imports the entire MyPackage.Util package:
import MyPackage.Util.*;
Flex searches the source path for imported files and packages, and includes only those that are used in the final SWF file.
It is not sufficient to simply specify the fully qualified class name. You should use fully qualified class names only when necessary to distinguish two classes with the same class name that reside in different packages.
If you import a class but do not use it in your application, the class is not included in the resulting SWF file's bytecode. As a result, importing an entire package with a wildcard does not create an unnecessarily large SWF file.
The following sample application, which calls a single function, shows several methods of separating ActionScript from the MXML.
The Temperature application takes input from a single input field and uses a function to convert the input from Fahrenheit to Celsius. It then displays the resulting temperature in a Label control.
The following code shows the ActionScript event handling logic inside the MXML tag's click event:
<?xml version="1.0"?>
<!-- usingas/ASOneFile.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
width="700">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel title="Temperature Application" width="90%">
<s:HGroup>
<s:Label text="Temperature in Fahrenheit:"/>
<s:TextInput id="fahrenheit" width="120"/>
<s:Button label="Convert"
click="celsius.text=String(Math.round((Number(fahrenheit.text)-32)/1.8 * 10)/10);"/>
<s:Label text="Temperature in Celsius:"/>
<s:Label id="celsius" width="120" fontSize="24"/>
</s:HGroup>
</s:Panel>
</s:Application>
In this example, the logic for the function is inside an <fx:Script> block in the MXML document, and is called from the MXML tag's click event, as the following code shows:
<?xml version="1.0"?>
<!-- usingas/ASScriptBlock.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
width="700">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public function calculate():void {
var n:Number = Number(fahrenheit.text);
var t:Number = Math.round((n-32)/1.8*10)/10;
celsius.text=String(t);
}
]]>
</fx:Script>
<s:Panel title="Temperature Application" width="90%">
<s:HGroup>
<s:Label text="Temperature in Fahrenheit:"/>
<s:TextInput id="fahrenheit" width="120"/>
<s:Button label="Convert" click="calculate();" />
<s:Label text="Temperature in Celsius:"/>
<s:Label id="celsius" width="120" fontSize="24"/>
</s:HGroup>
</s:Panel>
</s:Application>
Here, the function call is in an MXML event attribute, and the function is defined in a separate ActionScript file, as the following code shows:
<?xml version="1.0"?>
<!-- usingas/ASSourceFile.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
width="700">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<!-- Specify the ActionScript file that contains the function. -->
<fx:Script source="includes/Sample3Script.as"/>
<s:Panel title="Temperature Application" width="90%">
<s:HGroup>
<s:Label text="Temperature in Fahrenheit:"/>
<s:TextInput id="fahrenheit" width="120"/>
<s:Button label="Convert" click="celsius.text=calculate(fahrenheit.text);"/>
<s:Label text="Temperature in Celsius:"/>
<s:Label id="celsius" width="120" fontSize="24"/>
</s:HGroup>
</s:Panel>
</s:Application>
The Sample3Script.as ActionScript file contains the following code:
// usingas/includes/Sample3Script.as
public function calculate(s:String):String {
var n:Number = Number(s);
var t:Number = Math.round((n-32)/1.8*10)/10;
return String(t);
}
You can create reusable components that use ActionScript and reference these components in your applications as MXML tags. Components created in ActionScript can contain graphical elements, define custom business logic, or extend existing components. They can inherit from any components available in Flex.
Defining your own components in ActionScript has several benefits. Components let you divide your applications into individual modules that you can develop and maintain separately. By implementing commonly used logic within custom components, you can build a suite of reusable components that you can share among multiple applications.
Also, you can base your custom components on the set of components by extending from the Flex class hierarchy. You can create custom versions of Flex visual controls, as well as custom versions on nonvisual components, such as data validators, formatters, and effects.
For example, you can define a custom button, derived from the Button control, in the myControls package, as the following example shows:
package myControls {
import mx.controls.Button;
public class MyButton extends Button {
public function MyButton() {
...
}
...
}
}
In this example, you write your MyButton control to the MyButton.as file, and you store the file in the myControls subdirectory of the root directory of your application. The fully qualified class name of your component reflects its location. In this example, the component's fully qualified class name is myControls.MyButton.
You can reference your custom Button control from an application file, such as MyApp.mxml, as the following example shows:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:cmp="myControls.*"> <cmp:MyButton label="Jack"/> </s:Application>
In this example, you define the cmp namespace that defines the location of your custom component in the application's directory structure. You then reference the component as an MXML tag using the namespace prefix.
Typically, you put custom ActionScript components in directories that are in the source path. These include any directory that you specify in the source path.
You can also create custom components using MXML. For more information, see Custom components.
You can create the following types of components in ActionScript:
User-interface components contain both processing logic and visual elements. These components usually extend the component hierarchy. You can extend from the UIComponent classes, or any of the components, such as Button, ComboBox, or DataGrid. Your custom ActionScript component inherits all of the public methods, along with public and protected properties of its base class.
Nonvisual components define no visual elements. A nonvisual component is an ActionScript class that does not extend the UIComponent class. They can provide greater efficiency at run time.
Object introspection is a technique for determining the elements of a class at run time, such as its properties and methods. There are two ways to do introspection in ActionScript:
Using for..in loops
Using the introspection API
You might find object introspection a useful technique when debugging your application. For example, you might write a method that takes a generic object of type Object as an argument. You can use introspection to output all of the properties and methods of the Object to determine exactly what your application passed to it.
You can use a for..in loop to iterate over objects and output their properties and their values. A for..in loop enumerates only dynamically added properties. Declared variables and methods of classes are not enumerated in for..in loops. This means that most classes in the ActionScript API will not display any properties in a for..in loop. However, the generic type Object is still a dynamic object and will display properties in a for..in loop.
The following example creates a generic Object, adds properties to that object, and then iterates over that object when you click the button to inspect its properties:
<?xml version="1.0"?>
<!-- usingas/IntrospectionForIn.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initApp()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private var obj:Object = new Object();
private function initApp():void {
// Create the object.
obj.a = "Schotten Totten";
obj.b = "Taj Majal";
obj.c = "Durche die Wuste";
}
public function dumpObj():void {
for (var p:String in obj) {
ta1.text += p + ":" + obj[p] + "\n";
}
}
]]>
</fx:Script>
<s:TextArea id="ta1" width="400" height="200"/>
<s:Button label="Dump Object" click="dumpObj()"/>
</s:Application>
You can also use the mx.utils.ObjectUtil.toString() method to print all the dynamically added properties of an object, for example:
<?xml version="1.0"?>
<!-- usingas/ObjectUtilToString.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initApp()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.utils.ObjectUtil;
private var obj:Object = new Object();
private function initApp():void {
// Create the object.
obj.a = "Schotten Totten";
obj.b = "Taj Majal";
obj.c = "Durche die Wuste";
}
public function dumpObj():void {
ta1.text = ObjectUtil.toString(obj);
}
]]>
</fx:Script>
<s:TextArea id="ta1" width="400" height="200"/>
<s:Button label="Dump Object" click="dumpObj()"/>
</s:Application>
The mx.utils.ObjectUtil class has other useful methods such as compare(), copy(), and isSimple(). For more information, see the ActionScript 3.0 Reference for Apache Flex.
If you want to list all the public properties and methods of a nondynamic (or sealed) class or class instance, use the describeType() method and parse the results using the E4X API. The describeType() method is in the flash.utils package. The method's only parameter is the target object that you want to introspect. You can pass it any ActionScript value, including all available ActionScript types such as object instances, primitive types such as uint, and class objects. The return value of the describeType() method is an E4X XML object that contains an XML description of the object's type.
The describeType() method returns only public members. The method does not return private members of the caller's superclass or any other class where the caller is not an instance. If you call describeType(this), the method returns information only about nonstatic members of the class. If you call describeType(getDefinitionByName("MyClass")), the method returns information only about the target's static members.
The following example introspects the Button control and prints the details to TextArea controls:
<?xml version="1.0"?>
<!-- usingas/IntrospectionAPI.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="getDetails()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.utils.*;
public function getDetails():void {
// Get the Button control's E4X XML object description.
var classInfo:XML = describeType(button1);
// Dump the entire E4X XML object into ta2.
ta2.text = classInfo.toString();
// List the class name.
ta1.text = "Class " + classInfo.@name.toString() + "\n";
// List the object's variables, their values, and their types.
for each (var v:XML in classInfo..variable) {
ta1.text += "Variable " + v.@name + "=" + button1[v.@name] +
" (" + v.@type + ")\n";
}
// List accessors as properties.
for each (var a:XML in classInfo..accessor) {
// Do not get the property value if it is write only.
if (a.@access == 'writeonly') {
ta1.text += "Property " + a.@name + " (" + a.@type +")\n";
}
else {
ta1.text += "Property " + a.@name + "=" +
button1[a.@name] + " (" + a.@type +")\n";
}
}
// List the object's methods.
for each (var m:XML in classInfo..method) {
ta1.text += "Method " + m.@name + "():" + m.@returnType + "\n";
}
}
]]>
</fx:Script>
<s:Button label="This Button Does Nothing" id="button1"/>
<s:TextArea id="ta1" width="400" height="200"/>
<s:TextArea id="ta2" width="400" height="200"/>
</s:Application>
The output displays accessors, variables, and methods of the Button control, and appears similar to the following:
Class mx.controls::Button ... Variable id=button1 (String) Variable __width=66 (Number) Variable layoutWidth=66 (Number) Variable __height=22 (Number) Variable layoutHeight=22 (Number) ... Property label=Submit (String) Property enabled=true (Boolean) Property numChildren=2 (uint) Property enabled=true (Boolean) Property visible=true (Boolean) Property toolTip=null (String) ... Method dispatchEvent():Boolean Method hasEventListener():Boolean Method layoutContents():void Method getInheritingStyle():Object Method getNonInheritingStyle():Object
Another useful method is the ObjectUtil's getClassInfo() method. This method returns an Object with the name and properties of the target object. The following example uses the getClassInfo() and toString() methods to show the properties of the Button control:
<?xml version="1.0"?>
<!-- usingas/IntrospectionObjectUtil.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
height="650">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script><![CDATA[
import mx.controls.Alert;
import mx.utils.ObjectUtil;
private function showProps(b:Button):void {
var o:Object = ObjectUtil.getClassInfo(b);
ta1.text = ObjectUtil.toString(o);
}
]]>
</fx:Script>
<s:Button id="b1" label="Show Properties" click="showProps(b1)"/>
<s:TextArea id="ta1" width="300" height="500"/>
</s:Application>
Navigation
Adobe, Adobe AIR, Adobe Flash Platform, Adobe Flash Player and Adobe Flash Professional are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.