One of the common goals of creating MXML components is to create configurable and reusable components. For example, you might want to create MXML components that take properties, dispatch events, define new style properties, have custom skins, or use other customizations.
For information about how to create and deploy simple MXML components, including how to apply styles and skins to your MXML components, see Simple MXML components.
One design consideration when you create custom MXML components is reusability. That is, do you want to create a component that is tightly coupled to your application, or one that is reusable in multiple applications?
A tightly coupled component is written for a specific application, and is often dependent on the application's structure, variable names, or other details. If you change the application, you will probably need to modify the component to reflect that change, and it will also be difficult to use the component in another application without rewriting it.
Another possibility is to design a loosely coupled component for reuse. A loosely coupled component has a well-defined interface that specifies how to pass information to the component, and how the component passes back results to the application.
With loosely coupled components, you typically define properties of the component to let users pass information to it. These properties, defined by using variables or setter and getter methods, specify the data types of parameter values. For more information about defining component properties, see Adding custom properties and methods to a component.
The best practice for defining components that return information to the main application is to design the component to dispatch an event that contains the return data. In that way, the main application can define an event listener to handle the event and take the appropriate action. For more information on dispatching events, see Working with events.
MXML components provide you with a simple way to create ActionScript classes. When defining classes, you use class properties to store information and class methods to define class functionality. When creating MXML components, you can also add properties and methods to the components to make them configurable. By allowing the user to pass information to the components, you can create a reusable component that you can use in multiple locations throughout your application, or in multiple applications.
You can define methods for your MXML components in ActionScript, and properties in ActionScript or MXML. The Flex compiler converts the MXML component into an ActionScript class, so there is no performance difference between defining a property in MXML and defining it in ActionScript.
With ActionScript, you define properties and methods by using the same syntax that you use in an ActionScript class. For more information on using ActionScript to define properties and methods, see Custom ActionScript components.
When using ActionScript, you place a property or method definition within an <fx:Script> block. The <fx:Script> tag must be an immediate child tag of the root tag of the MXML file. A public variable declaration or a set function in an <fx:Script> tag becomes a property of the component. A public ActionScript function in an <fx:Script> tag becomes a method of the component.
In the following example, the component defines two data providers to populate the ComboBox control, and a function to use as the event listener for the creationComplete event. This function sets the data provider of the ComboBox based on the value of the shortNames property. By default, the shortNames property is set to true, to display two-letter names.
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPropAS.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="setNameLength();">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
// Define public variables.
public var shortNames:Boolean = true;
// Define private variables.
private var stateArrayShort:ArrayList = new ArrayList(["AK", "AL"]);
private var stateArrayLong:ArrayList = new ArrayList(["Arkansas", "Alaska"]);
// Define listener method.
public function setNameLength():void {
if (shortNames) {
dataProvider=stateArrayShort; }
else {
dataProvider=stateArrayLong; }
}
]]>
</fx:Script>
</s:ComboBox>
The following MXML application file uses the <MyComp:StateComboBoxPropAS> tag to configure the control to display long state names:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPropAS.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<MyComp:StateComboBoxPropAS shortNames="true"/>
</s:Application>
The following example modifies the component to add a method that lets you change the display of the state name at run time. This public method takes a single argument that specifies the value of the shortNames property.
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPropMethod.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="setNameLength();">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
// Define public variables.
public var shortNames:Boolean = true;
// Define private variables.
private var stateArrayShort:ArrayList = new ArrayList(["AK", "AL"]);
private var stateArrayLong:ArrayList = new ArrayList(["Arkansas", "Alaska"]);
public function setNameLength():void {
if (shortNames) {
this.dataProvider=stateArrayShort; }
else {
this.dataProvider=stateArrayLong; }
}
public function setShortName(val:Boolean):void {
shortNames=val;
if (val) {
dataProvider=stateArrayShort; }
else {
dataProvider=stateArrayLong; }
}
]]>
</fx:Script>
</s:ComboBox>
You might use this new method with the click event of a Button control to change the display from long names to short names, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPropWithMethod.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<MyComp:StateComboBoxPropMethod id="myCB"
shortNames="false"/>
<s:Button label="Use Short Names"
click="myCB.setShortName(true);"/>
</s:Application>
In MXML, you can use an MXML tag to define a property of any type, as long as the type refers to an ActionScript class name. For example, you can use the <fx:String>, <fx:Number>, and <fx:Boolean> tags to define properties in your MXML components that take String, Number, or Boolean values, respectively. When using one of these tags, you must specify an id, which becomes the property name.
Optionally, you can specify an initial value in the body of the tag, or you can use the source property to specify the contents of an external URL or file as the initial property value. If you use the source property, the body of the tag must be empty. The initial value can be static data or a binding expression.
The following examples show initial properties set as static data and binding expressions. Values are set in the tag bodies and in the source properties.
<!-- Boolean property examples: -->
<fx:Boolean id="myBooleanProperty">true</fx:Boolean>
<fx:Boolean id="passwordStatus">{passwordExpired}</fx:Boolean>
<!-- Number property examples: -->
<fx:Number id="myNumberProperty">15</fx:Number>
<fx:Number id="minutes">{numHours * 60}</fx:Number>
<!-- String property examples: -->
<fx:String id="myStringProperty">Welcome, {CustomerName}.</fx:String>
<fx:String id="myStringProperty1" source="./file"/>
All properties defined by using the <fx:String>, <fx:Number>, and <fx:Boolean> tags are public. This means that the component user can access these properties.
The following example modifies the example in Defining properties and methods in ActionScript to define the shortNames property by using an MXML tag, rather than an ActionScript variable definition:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPropMXML.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="setNameLength();">
<fx:Declarations>
<!-- Control display of state names. -->
<fx:Boolean id="shortNames">true</fx:Boolean>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
// Define private variables.
private var stateArrayShort:ArrayList = new ArrayList(["AK", "AL"]);
private var stateArrayLong:ArrayList = new ArrayList(["Arkansas", "Alaska"]);
// Define listener method.
public function setNameLength():void {
if (shortNames) {
dataProvider=stateArrayShort; }
else {
dataProvider=stateArrayLong; }
}
]]>
</fx:Script>
</s:ComboBox>
In the preceding example, you implement the StateComboBox.mxml file by using the <fx:Boolean> tag to add a new property, shortNames, with a default value of true. This property controls whether the ComboBox control displays state names that use a two-letter format, or the entire state name.
You can define properties for your MXML components by using setter and getter methods. The advantage of getters and setters is that they isolate the variable from direct public access so that you can perform the following tasks:
Inspect and validate any data written to the property on a write operation
Trigger events that are associated with the property when the property changes
Calculate a return value on a read operation
For more information, see Custom ActionScript components.
In the following example, the StateComboBoxGetSet.mxml component contains several new properties and methods:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxSetGet.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
// Define private variables.
private var stateArrayShort:ArrayList = new ArrayList(["AK", "AL"]);
private var stateArrayLong:ArrayList = new ArrayList(["Arkansas", "Alaska"]);
// Variable holding the display setting.
private var __shortNames:Boolean = true;
// Set method.
public function set shortNames(val:Boolean):void {
// Call method to set the dataProvider
// based on the name length.
__shortNames = val;
if (__shortNames) {
this.dataProvider=stateArrayShort; }
else {
this.dataProvider=stateArrayLong; }
}
// Get method.
public function get shortNames():Boolean{
return __shortNames;
}
]]>
</fx:Script>
</s:ComboBox>
In this example, you create a StateComboBoxGetSet.mxml control that takes a shortNames property defined by using ActionScript setter and getter methods. One advantage to using setter and getter methods to define a property is that the component can recognize changes to the property at run time. For example, you can give your users the option of displaying short state names or long state names from the application. The setter method modifies the component at run time in response to the user's selection.
You can also define events to be dispatched when a property changes. This enables you to signal the change so that an event listener can recognize the change. For more information on events, see Working with events.
You can call a component's custom methods and access its properties in ActionScript just as you would any instance method or component property, as the following application shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPropSetGet.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<MyComp:StateComboBoxSetGet id="myStateCB"
shortNames="true"/>
<s:Button label="Toggle Short Names"
click="myStateCB.shortNames=!myStateCB.shortNames;"/>
</s:Application>
In this example, selecting the button toggles the display format of the state name between the short and long formats.
You should precede the variable or set function with the [Inspectable] metadata tag if you plan to use the component in an authoring tool. The [Inspectable] metadata tag must immediately precede the property's variable declaration or the setter and getter methods to be bound to that property, as the following example shows:
<fx:Script> <![CDATA[ // Define public variables. [Inspectable(defaultValue=true)] public var shortNames:Boolean = true; ]]> </fx:Script>
For more information on the [Inspectable] metadata tag, see Metadata tags in custom components.
The Flex data binding mechanism provides a syntax for automatically copying the value of a property of one object to a property of another object at run time. The following example shows a Text control that gets its data from Slider control's value property. The property name inside the curly braces ({ }) is a binding expression that copies the value of the source property, mySlider.value, to the destination property, the Text control's text property, as the following example shows:
<mx:Slider id="mySlider"/>
<mx:Text text="{mySlider.value}"/>
Data binding is usually triggered whenever the value of the source property changes.
Properties that you define in your custom controls can also take advantage of data binding. You can automatically use any property defined by using an MXML tag, such as <fx:Boolean>, and any ActionScript property defined as a variable or defined by using setter and getter methods as the destination of a binding expression.
For example, Defining properties by using setters and getters defined the shortNames property of StateComboBoxGetSet.mxml by using setter and getter methods. With no modification to that component, you can use shortNames as the destination of a binding expression, as the following example shows:
<MyComp:StateComboBoxSetGet shortNames="{some_prop}"/>
However, you can also write your component to use the shortNames property as the source of a binding expression, as the following example shows for the component StateComboBoxGetSetBinding.mxml:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPropSetGetBinding.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<MyComp:StateComboBoxSetGetBinding id="myStateCB"
shortNames="false"/>
<s:TextArea
text="The value of shortNames is {myStateCB.shortNames}"/>
<s:Button label="Toggle Short Names"
click="myStateCB.shortNames=!myStateCB.shortNames;"/>
</s:Application>
When a property is the source of a data binding expression, any changes to the property must signal an update to the destination property. The way to signal that change is to dispatch an event, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxSetGetBinding.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
import flash.events.Event;
// Define private variables.
private var stateArrayShort:ArrayList = new ArrayList(["AK", "AL"]);
private var stateArrayLong:ArrayList = new ArrayList(["Arkansas", "Alaska"]);
private var __shortNames:Boolean = true;
public function set shortNames(val:Boolean):void {
__shortNames = val;
if (__shortNames) {
dataProvider=stateArrayShort; }
else {
dataProvider=stateArrayLong; }
// Create and dispatch event.
dispatchEvent(new Event("changeShortNames"));
}
// Include the [Bindable] metadata tag.
[Bindable(event="changeShortNames")]
public function get shortNames():Boolean {
return __shortNames;
}
]]>
</fx:Script>
</s:ComboBox>
Define the property as a variable, or by using setter and getter methods.
You must define a setter method and a getter method if you use the [Bindable] tag with the property.
Insert the [Bindable] metadata tag before the property definition, or before either the setter or getter method, and optionally specify the name of the event dispatched by the property when it changes.
If you omit the event name specification from the [Bindable] metadata tag, Flex automatically generates and dispatches an event named propertyChange. If the property value remains the same on a write, Flex does not dispatch the event or update the property.
Alternatively, you can place the [Bindable] metadata before a public class definition. This makes all public properties that you defined as variables, and all public properties that you defined by using both a setter and a getter method, usable as the source of a binding expression.
Add a call to the dispatchEvent() method to dispatch the event when you define the event name in the [Bindable] metadata tag.
For more information on using the [Bindable] tag, see Bindable metadata tag.
One of the ways that you can make a component reusable is to design it so that users can pass values to the component by using public properties of the component. For information on how to define properties for MXML components by using MXML and ActionScript, and how to pass values to those properties, see Supporting data binding in custom properties.
Rather than passing a value to a component, you can pass a reference to it. The reference could be to the calling component, to another component, or to a property of a component.
The Application object is the top-level object in a Flex application. Often, you must reference properties or objects of the Application object from your custom component. Use the mx.core.FlexGlobals.topLevelApplication static property to reference the application object.
You can also use the parentDocument property to reference the next object up in the document chain of a Flex application. The parentDocument property is inherited by all components from the UIComponent class. For an MXML component, the parentDocument property references the Object corresponding to the component that referenced the MXML component.
For more information on the mx.core.FlexGlobals.topLevelApplication static property and the parentDocument property, see Application containers.
Even if the calling file does not pass a reference to the Application object, you can always access it from your MXML component. For example, the following application contains a custom component called StateComboBoxDirectRef. In this example, StateComboBoxDirectRef is designed to write the index of the selected item in the ComboBox to the TextArea control:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainDirectRef.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:TextArea id="myTAMain"/>
<MyComp:StateComboBoxDirectRef/>
</s:Application>
The simplest way to write StateComboBoxDirectRef.mxml is to use the mx.core.FlexGlobals.topLevelApplication static property to write the index directly to the TextArea control, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxDirectRef.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
close="handleCloseEvent(event);">
<fx:Script>
<![CDATA[
import flash.events.Event;
import mx.core.FlexGlobals;
public function handleCloseEvent(eventObj:Event):void {
mx.core.FlexGlobals.topLevelApplication.myTAMain.text=
String(this.selectedIndex);
}
]]>
</fx:Script>
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
In the previous example, you use the close event of the ComboBox control to write the selectedIndex directly to the TextArea control in the main application. You must cast the value of selectedIndex to a String because the text property of the TextArea control is of type String.
You could make the custom component slightly more reusable by using the parentDocument property to reference the TextArea control, rather than the mx.core.FlexGlobals.topLevelApplication static property. By using the parentDocument property, you can call the custom component from any other MXML component that contains a TextArea control named myTAMain, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxDirectRefParentObj.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
close="handleCloseEvent(event);">
<fx:Script>
<![CDATA[
import flash.events.Event;
public function handleCloseEvent(eventObj:Event):void {
parentDocument.myTAMain.text=String(selectedIndex);
}
]]>
</fx:Script>
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
Although these examples work, they require that the TextArea control has a predefined id property, and that MXML component knows that id. In this case, the custom component is an example of a tightly coupled component. That is, the component is written for a specific application and application structure, and it is not easily reused in another application.
A loosely coupled component is a highly reusable component that you can easily use in different places in one application, or in different applications. To make the component from Supporting data binding in custom properties reusable, you can pass a reference to the TextArea control to the custom component, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPassRefToTA.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:TextArea id="myTAMain" />
<MyComp:StateComboBoxPassRefToTA outputTA="{myTAMain}" />
</s:Application>
The custom component does not have to know anything about the main application, other than that it writes its results back to a TextArea control, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPassRefToTA.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
close="handleCloseEvent(event);">
<fx:Script>
<![CDATA[
import flash.events.Event;
import spark.components.TextArea;
// Define a variable of type mx.controls.TextArea.
public var outputTA:TextArea;
public function handleCloseEvent(eventObj:Event):void {
outputTA.text=String(this.selectedIndex);
}
]]>
</fx:Script>
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
In this example, you use the Flex data binding syntax to pass the reference to the TextArea control to your custom component. Now, you can use StateComboBoxPassRefToTA.mxml anywhere in an application. The only requirement is that the calling component must pass a reference to a TextArea control to the component.
In Passing a reference to the component, you passed a reference to a single component to the custom MXML component. This allowed the MXML component to access only a single component in the main application.
One type of reference that you can pass to your component is a reference to the calling component. With a reference to the calling component, your custom MXML file can access any properties or object in the calling component.
To pass a reference to the calling component to a custom MXML component, you create a property in the custom MXML component to represent the calling component. Then, from the calling component, you pass the reference, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/CallingComponent.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout horizontalAlign="left"/>
</s:layout>
<!-- Use the caller property to pass a reference to the
calling component to DestinationComp. -->
<s:Label text="Enter text"/>
<s:TextInput id="text1" text="Hello"/>
<s:Label text="Input text automatically copied to MXML component."/>
<MyComp:DestinationComp caller="{this}"/>
</s:Application>
In the definition of DestinationComp.mxml, you define the caller property, and specify as its data type the name of the file of the calling MXML file, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/DestinationComp.mxml -->
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
// Define variable to reference calling file.
[Bindable]
public var caller:CallingComponent;
]]>
</fx:Script>
<s:TextInput id="mytext"
text="{caller.text1.text}"/>
</s:VGroup>
Remember, an MXML component corresponds to an ActionScript class, where the ActionScript class name is the filename of the MXML component. Therefore, the MXML component defines a new data type. You can then create a variable whose data type is that of the calling file.
With the reference to the calling file, your MXML component can access any property of the calling file, and you can bind the value of the TextInput control in CallingComp.mxml to the TextInput control in StateComboBox.mxml. Creating a property of type CallingComp provides strong typing benefits and ensures that binding works correctly.
Flex applications are event-driven. Events let a programmer know when the user interacts with the interface, and also when important changes happen in the appearance or life cycle of a component, such as the creation or destruction of a component or its resizing. You can handle events that your custom components generate and add your own event types to your custom components.
Simple MXML components are those that contain a single root tag that is not a container. In this topic, the StateComboBox.mxml component is a simple component because it contains a definition only for the ComboBox control.
You have two choices for handling events that a simple component dispatches: handle the events within the definition of your MXML component, or allow the file that references the component to handle them.
The following example uses the StateComboBox.mxml component, and defines the event listener for the component's close event in the main application:
<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"
xmlns:MyComp="*">
<fx:Script>
<![CDATA[
import flash.events.Event;
public function handleCloseEvent(eventObj:Event):void {
...
}
]]>
</fx:Script>
<MyComp:StateComboBox rowCount="5" close="handleCloseEvent(event);"/>
</s:Application>
In this example, if the MXML component dispatches a close event, the event listener in the calling MXML file handles it.
Alternatively, you could define the event listener within the StateComboBox.mxml component, as the following example shows:
<?xml version="1.0"?>
<!-- StateComboBox.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
close="handleCloseEvent(event);">
<fx:Script>
<![CDATA[
import flash.events.Event;
public function handleCloseEvent(eventObj:Event):void {
...
}
]]>
</fx:Script>
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
With simple MXML components, you can define event listeners in both places, and both event listeners process the event. However, the event listeners defined within the component execute before any listeners defined in the application.
All MXML components can dispatch events, either those inherited by the components from their superclasses, or new events that you define within your components. When you are developing MXML components, you can add your own event types.
In this example, you define a new component called TextAreaEnabled.mxml that uses a <s:TextArea> tag as its root tag. This component also defines a new property called enableTA that users set to true to enable text input or to false to disable input.
The setter method dispatches a new event type, called enableChanged, when the value of the enableTA variable changes. The [Event] metadata tag identifies the event to the MXML compiler so that the file referencing the component can use the new property. For more information on using the [Event] metadata keyword, see Metadata tags in custom components.
The syntax for the [Event] metadata tag is as follows:
<fx:Metadata> [Event(name="eventName", type="eventType")] </fx:Metadata>
You dispatch new event types by using the dispatchEvent() method, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/TextAreaEnabled.mxml -->
<s:TextArea xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" >
<fx:Metadata>
[Event(name="enableChanged", type="flash.events.Event")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import flash.events.Event;
// Define private variable to hold the enabled state.
private var __enableTA:Boolean;
// Define a setter method for the private variable.
public function set enableTA(val:Boolean):void {
__enableTA = val;
enabled = val;
// Define event object, initialize it, then dispatch it.
dispatchEvent(new Event("enableChanged"));
}
// Define a getter method for the private variable.
public function get enableTA():Boolean {
return __enableTA;
}
]]>
</fx:Script>
</s:TextArea>
The following main application includes TextAreaEnabled.mxml and defines an event listener for the enableChanged event:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainTextAreaEnable.mxml -->
<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"
xmlns:MyComp="myComponents.*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.events.Event;
import myComponents.TextAreaEnabled;
public function handleEnableChangeEvent(eventObj:Event):void {
var tempTA:TextAreaEnabled =
eventObj.currentTarget as TextAreaEnabled;
if (tempTA.enableTA) {
myButton.label="Click to disable";
}
else {
myButton.label="Click to enable";
}
}
]]>
</fx:Script>
<MyComp:TextAreaEnabled id="myTA" enableTA="false"
enableChanged="handleEnableChangeEvent(event);" />
<s:Button id="myButton" label="Click to enable"
click="myTA.enableTA=!myTA.enableTA;" />
</s:Application>
If you do not use the [Event] metadata tag in the custom component file to define the enableChanged event, the MXML compiler generates an error message when you reference the event name in an MXML file. Any component can register an event listener for the event in ActionScript using the addEventListener() method, even if you omit the [Event] metadata tag.
You can also create and dispatch events that use an event object of a type other than that defined by the Event class. For example, you might want to create an event object that contains new properties so that you can pass those properties back to the referencing file. To do so, you create a subclass of the Event class to define your new event object. For information on creating custom event classes, see Custom events.
Composite components are components that use a container for the root tag, and define child components in that container. You handle events generated by the root container in the same way as you handle events generated by simple MXML components. That is, you can handle the event within the MXML component, within the referencing file, or both. For more information, see Handling events from simple MXML components.
To handle an event that a child of the root container dispatches, you can handle it in the MXML component in the same way as you handle an event from the root container. However, if a child component of the root container dispatches an event, and you want that event to be dispatched to the referencing file, you must add logic to your custom component to propagate the event.
For example, you can define a component that uses an <mx:Form> tag as the root tag, and include within it a ComboBox control. Any event that the Form container dispatches, such a scroll event, is dispatched to the referencing file of the custom component. However, the close event of the ComboBox control is dispatched only within the custom MXML component.
To propagate the close event outside of the custom component, you define an event listener for it in the MXML component that redispatches it, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/AddressForm.mxml -->
<s:Form xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:local="*">
<fx:Metadata>
[Event(name="close", type="flash.events.Event")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import flash.events.Event;
// Redispatch event.
private function handleCloseEventInternal(eventObj:Event):void {
dispatchEvent(eventObj);
}
]]>
</fx:Script>
<s:FormItem label="Name">
<s:TextInput id="name1" />
</s:FormItem>
<s:FormItem label="Street">
<s:TextInput id="street" />
</s:FormItem>
<s:FormItem label="City" >
<s:TextInput id="city" />
</s:FormItem>
<s:FormItem label="State" >
<s:ComboBox close="handleCloseEventInternal(event);">
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
</s:FormItem>
</s:Form>
In this example, you propagate the event to the calling file. You could, alternatively, create an event type and new event object as part the propagation. For more information on the [Event] metadata tag, see Metadata tags in custom components.
You can handle the close event in your main application, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainAddressFormHandleEvent.mxml -->
<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"
xmlns:MyComp="myComponents.*"
height="600">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.events.Event;
private function handleCloseEvent(eventObj:Event):void {
myTAClose.text=eventObj.type;
}
private function handleMouseDown(eventObj:Event):void {
myTA.text=eventObj.type;
}
]]>
</fx:Script>
<s:TextArea id="myTA" />
<s:TextArea id="myTAClose" />
<MyComp:AddressForm mouseDown="handleMouseDown(event);"
close="handleCloseEvent(event);"/>
</s:Application>
Interfaces are a type of class that you design to act as an outline for your components. When you write an interface, you provide only the names of public methods rather than any implementation. For example, if you define two methods in an interface and then implement that interface, the implementing class must provide implementations of those two methods.
Interfaces in ActionScript can declare methods and properties only by using setter and getter methods; they cannot specify constants. The benefit of interfaces is that you can define a contract that all classes that implement that interface must follow. Also, if your class implements an interface, instances of that class can also be cast to that interface.
Custom MXML components can implement interfaces just as other ActionScript classes can. To do this, you use the implements attribute. All MXML tags support this attribute.
The following code is an example of a simple interface that declares several methods:
// The following is in a file named SuperBox.as.
interface SuperBox {
function selectSuperItem():String;
function removeSuperItem():Boolean;
function addSuperItem():Boolean;
}
A class that implements the SuperBox interface uses the implements attribute to point to its interface and must provide an implementation of the methods. The following example of a custom ComboBox component implements the SuperBox interface:
<?xml version="1.0"?>
<!-- StateComboBox.mxml -->
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="SuperBox">
<fx:Script>
<![CDATA[
public function selectSuperItem():String {
return "Super Item was selected";
}
public function removeSuperItem():Boolean {
return true;
}
public function addSuperItem():Boolean {
return true;
}
]]>
</fx:Script>
<s:dataProvider>
<s:ArrayList>
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
You can implement multiple interfaces by separating them with commas, as the following example shows:
<s:ComboBox ... implements="SuperBox, SuperBorder, SuperData">
All methods that you declare in an interface are considered public. If you define an interface and then implement that interface, but do not implement all of its methods, the MXML compiler throws an error.
Methods that are implemented in the custom component must have the same return type as their corresponding methods in the interface. If no return type is specified in the interface, the implementing methods can declare any return type.
You cannot define a constructor for an MXML component. If you do, the Flex compiler issues an error message that specifies that you defined a duplicate function.
For many types of Flex components, you can use an event listener instead of a constructor. For example, depending on what you want to do, you can write an event listener for the preinitialize, initialize, or creationComplete event to replace the constructor.
These events are all defined by the UIComponent class, and inherited by all of its subclasses. If you create an MXML component that is not a subclass of UIComponent, you cannot take advantage of these events. You can instead implement the IMXMLObject interface in your MXML component, and then implement the IMXMLObject.initialized() method, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/ObjectComp.mxml -->
<fx:Object xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IMXMLObject">
<fx:Script>
<![CDATA[
// Implement the IMXMLObject.initialized() method.
public function initialized(document:Object, id:String):void {
trace("initialized, x = " + x);
}
]]>
</fx:Script>
<fx:Declarations>
<fx:Number id="y"/>
<fx:Number id="z"/>
<fx:Number id="x"/>
</fx:Declarations>
</fx:Object>
Flex calls the IMXMLObject.initialized() method after it initializes the properties of the component. The following example uses this component:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainInitObject.mxml -->
<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"
xmlns:MyComp="myComponents.*"
creationComplete="initApp();">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public function initApp():void {
myTA.text="myFC.x = " + String(myFC.x);
}
]]>
</fx:Script>
<fx:Declarations>
<MyComp:ObjectComp id="myFC" x="1" y="2" z="3"/>
</fx:Declarations>
<s:TextArea id="myTA"/>
</s:Application>
Because Flex calls the IMXMLObject.initialized() method after it initializes the properties of the component, the trace() function in the implementation of the IMXMLObject.initialized() method outputs the following:
initialized, x = 1
Navigation
Adobe and Adobe Flash Platform 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.