Skip to content
Frank Wienberg edited this page Apr 18, 2017 · 2 revisions

MXML

An MXML file uses the extension .mxml and contains XML code that declares one ActionScript class. The name of the file determines the name of the class to define. The relative directory path determines the package of the class.

For example, if your source folder is src, a file in src/com/acme/MyClass.mxml would declare the ActionScript class com.acme.MyClass through MXML.

Syntax

MXML is an XML dialect, and as such starts with a directive which states the XML version and the character encoding:

<xml version="1.0" encoding="UTF-8"?>

Like any XML file, an MXML file must contain exactly one root element. An element consists of a self-closing tag, or of one opening and a corresponding closing tag. Element names come from a namespace that has to be declared using the attribute xmlns. The standard namespace for Flex 4 is http://ns.adobe.com/mxml/2009, which declares some meta-tags as well as elements for ActionScript's built-in types.

The simplest possible MXML class declaration would be:

<xml version="1.0" encoding="UTF-8"?>
<Object xmlns="http://ns.adobe.com/mxml/2009"/>

Using separate opening and closing tags and an XML comment, this becomes

<xml version="1.0" encoding="UTF-8"?>
<!-- My first MXML class! -->
<Object xmlns="http://ns.adobe.com/mxml/2009">
</Object>

Like XML elements, MXML must be nested properly (well-formed). They can represent either objects or properties. Elements representing objects can have XML attributes that represent their properties. Elements representing properties must be nested directly inside an object element and cannot have any properties (a Jangaroo exception is discussed below). The content of a property node declares its value. The value can be a primitive value, ActionScript code, an ActionScript expression (in curly braces {...}) or again be an object node, or even a list of object nodes.

<xml version="1.0" encoding="UTF-8"?>
<Object xmlns="http://ns.adobe.com/mxml/2009">
  <!-- property node with literal value: -->
  <foo>
    FOO
  </foo>
  <!-- property node with nested object: -->
  <bar>
    <!-- property value given as attribute: -->
    <Object baz="BAZ"/>
  </bar>
  <!-- property node with nested objects: -->
  <list>
    <Object name="first"/>
    <Object name="second"/>
  </list>
</Object>

In Flex, you can nest object nodes directly in an object node, but this is just a shorthand for declaring the value of the default property that has to be declared in the outer element's class. This feature is currently not supported by Jangaroo.

To be able to reference different namespaces, you can assign a local reference to a namespace. The namespace declaration we saw above is called the default namespace. When using a named local reference for a namespace, this identifier has to be used for every node from that namespace, like so:

<xml version="1.0" encoding="UTF-8"?>
<fx:Object xmlns:fx="http://ns.adobe.com/mxml/2009">
  <fx:foo>
    FOO
  </fx:foo>
  <fx:bar>
    <fx:Object baz="BAZ"/>
  </fx:bar>
  <fx:list>
    <fx:Object name="first"/>
    <fx:Object name="second"/>
  </fx:list>
</fx:Object>

While the local reference could be any arbitrary identifier, there are and should be conventions for which identifier to use for which namespace. In Flex 4, the convention for the Flex standard namespace is to use fx (as in the example above).

An important element to define arbitrary ActionScript class members is <fx:Script>. An MXML file may declare multiple Script elements, which all contribute to the declared ActionScript class. Also, import declarations are placed inside Script elements.

Referencing a Class

An MXML object node references an ActionScript class (that can also be declared in MXML). It does so through the node's namespace reference and its local name.

In ActionScript, other ActionScript classes are referenced through their fully qualified name, consisting of package name and class name, separated by a dot, e.g. com.acme.MyClass.

In MXML, there are two different ways to reference a class: one that uses the package name, and one using a component package (aka component library).

Namespaces based on package name look like you would refer to a package in an import statement in ActionScript:

<xml version="1.0" encoding="UTF-8"?>
<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*"/>

Here, the namespace com.acme.* corresponds to the package com.acme and is assigned the local namespace reference ac. Note that even when the Flex standard namespace is not used, it must be declared to identify the XML file as MXML.

Component packages can be defined in another XML format (more on that later) and are assigned a namespace URL. Both Flex 3 and 4 component packages feature such a URL. Component packages are used like a facade: They provide a single namespace for classes from different packages and can even use different local names to resolve name clashes.

FlExt AS defines a component library for all standard Ext components under the URL exml:ext.config (the name can only be explained in a historic context, so just take it as it is). We recommend using the local namespace reference ext, x, or, as in FlExt AS, you will mostly use Ext components, the default namespace.

What MXML Class References Mean

Essentially, MXML declares an object graph, so each MXML element represents an instance of the type it refers to, customized by the given properties and sub-elements.

One exception is the MXML root node. Because an MXML file declares a class, not an object instance, the root MXML class reference serves as the superclass of the class to define.

Roughly, you can picture an MXML class generating an ActionScript class like follows.

src/com/acme/MySubClass.mxml:

<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <ac:children>
    <ac:MyClass property1="first"/>
    <ac:MyClass property2="42"/>
  </ac:children>
</ac:MyClass>

The generated ActionScript class would look like so (simplified):

package com.acme {

public class MySubClass extends MyClass {

  public function MySubClass() {
    var children_1:MyClass = new MyClass();
    children_1.property1 = "first";

    var children_2:MyClass = new MyClass();
    children_2.property2 = 42;

    children = [
      children_1,
      children_2
    ];
  }
}

Assigning Properties

In MXML, object element attributes or sub-elements can be used to assign property values. Use the name of the property as attribute name. For a property sub-element, use the same namespace reference as the surrounding object, and the property name as the element's local name.

The property value can be given in one of three ways:

  1. As a simple literal like 123, "Hello", or true.
  2. As an ActionScript expression, enclosed in curly braces: {1+2}, {someVariable}, {obj.method(param)}.
  3. As nested MXML elements, where one element represens an object and many elements represent an Array of objects.

Options 1 and 2 can be given either as a quoted XML attribute value or as a text node nested into the property element. As always in XML, certain characters like < and & have to be escaped using XML entities (&lt;, &amp;).

<fx:Object someString="Hello" someNumber="{1+2}" someBoolean="true">
  <fx:anotherString>Me &amp; Bobby McGee</fx:anotherString>
  <fx:anotherNumber>{3 + 4}</fx:anotherNumber>
</fx:Object>

Note that it is illegal to declare the same property by an attribute and a sub-element.

To avoid entity escaping, text nodes can be wrapped in CDATA sections, like so:

<fx:Object>
  <fx:anotherString><![CDATA[Me & Bobby McGee]]></fx:anotherString>
</fx:Object>

Since ActionScript code frequently contains & characters, it is recommended to wrap all non-trivial code fragments in CDATA sections.

Declaring Properties

In ActionScript, Object is a dynamic class, which means that arbitrary properties can be used. These expando properties are always untyped, or typed by the ActionScript type *. When using literal values for untyped properties, since they are always strings, MXML uses type guessing: What looks like a number evaluates to a number, same for boolean, everything else is treated as a string. To prevent type guessing, you have to use an expression with the corresponding ActionScript syntax. For example, to force a number to be treated as a string, use

<fx:Object foo="{'123'}"/>

Note that you can use single and double quotes for both XML attributes and ActionScript strings, so

<fx:Object foo='{"123"}'/>

is also allowed and represents the same property value.

Declaring Properties in ActionScript

Most objects in ActionScript have a type that is defined by a class or interface that declare properties with a type.

In ActionScript, there are two ways to declare a (typed) property: As a field, or through accessor functions.

package com.acme {

public class MyClass {
  public var property1:String;

  private var _property2;

  public function get property2():int {
    return _property2;
  }
  
  public function set property2(value:int):void {
    this._property2 = value;
  }
}

For a property to be assignable from MXML, it must be writable (not read-only). Fields are writable when they are declared using var (as opposed to using const). For accessor-declared properties, it suffices that the set accessor is present. So technically, MXML can even set "write-only" properties.

<ac:MyClass xmlns="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*"
            property1="Hello World"
            property2="42"/>

When using a typed property, the MXML compiler can detect type errors. It also refrains from type guessing. In the above example, using property1="123" would result in property1 having the string value "123", not the number 123, because it has the type String.

ActionScript only has very limited support for generic types. There is only one generic type, Vector, and an annotation to declare the element type of an Array. This annotation should be used so that the MXML compiler knows about the type of nested MXML elements.

package com.acme {

public class MyClass {
  ...

  [ArrayElementType("com.acme.MyClass")]
  public var children:Array;
}

In the ArrayElementType annotation, the type always has to be given by its fully-qualified name. In this example, the MXML compiler would detect that the second element has the wrong type:

<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <ac:children>
    <ac:MyClass property1="first"/>
    <fx:Object foo="bar"/>
  </ac:children>
</ac:MyClass>

Strong typing not only helps find errors, but also is key to your IDE coming up with good suggestions when using code completion.

Declaring Properties in MXML

To declare properties of an MXML class, you can simply use an <fx:Script> elements with the corresponding ActionScript code. Note that we follow the recommendation to wrap code in a CDATA section.

<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <fx:Script><![CDATA[
    public var property3:Boolean = true;
  ]]></fx:Script>
</ac:MyClass>

This example class extends MyClass and declares an additional property property3 of type Boolean with default value true.

Now imagine you want to declare a property like children in the ActionScript example above that can contain nested objects, and you want to give it a default value. Of course, you could do that in ActionScript, too, but why fall back to code when you are using the declarative language MXML?

For this use case, MXML provides the element <fx:Declarations>. The Declarations element declares properties in MXML, so it is limited to class-typed properties. Its advantage is that the default value can be defined by nested MXML elements.

<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <fx:Declarations>
    <fx:Array id="related">
      <ac:MyClass property1="first"/>
      <ac:MyClass property1="second"/>
    </fx:Array>
  </fx:Declarations>
</ac:MyClass>

This example declares the property related of type Array (unfortunately, unlike in ActionScript, in MXML, you cannot declare the array element type), and defines the default value declaratively as MXML sub-elements.

Code Documentation

ActionScript supports documentation comments like the ones known from JavaScript, Java and other languages.

package com.acme {

/**
 * This is the class documentation.
 */
public class MyClass {

  /**
   * This is a class member documentation.
   * @param input the input parameter
   * @return the method result
   */
  public function doSomething(input:String):int {
    ...
  }
}

In Script blocks, MXML also supports ActionScript documentation comments. For MXML declarations, the documentation comments are placed directly into the XML code and thus resemble XML comments. Just like ActionScript documentation comments are ActionScript block comments (/* ... */) starting with an additional asterisk (/** ... */), MXML documentation comments are XML comments (<!-- ... -->) starting with an additional dash (<!--- ... -->).

<!--- 
  - This is the class documentation.
  -->
<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <fx:Declarations>
    <!---
      - This is the documentation of property 'related'.
      -->
    <fx:Array id="related"/>
  </fx:Declarations>
</ac:MyClass>

Class Annotations

ActionScript supports annotations on classes and class members. An annotation is placed before the annotated element and enclosed in square brackets ([...]).

In MXML, the element <fx:Metadata> is used to declare class annotations. Since the class is declared by the root element, and in XML, there must not be multiple root elements, this element is nested inside the root element. It contains the annotation in the normal ActionScript syntax.

<ac:MyClass xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:ac="com.acme.*">
  <fx:Metadata>[Bindable]</fx:Metadata>
</ac:MyClass>

Events

In addition to properties, ActionScript objects can declare events that they emit. While in original Flex, such event sources must implement flash.events.IEventDispatcher, for Jangaroo, this has been adapted to Ext, where an event dispatcher is called an "observable", and there is a mixin represented by the Ext AS interface ext.mixin.IObservable and the class ext.util.Observable. Every Ext component is observable (ext.Component inherits from ext.util.Observable) and thus can emit events.

While in Ext JS, the events are only declared by documentation comments, Flex supports an Event annotation that defines name and type of an emitted event. Whenever a class declares an event through such an annotation, the event name can be used similar to a property.

While Ext JS documents event callback function signatures, Flex lets you declare an event type. To build a bridge between Flex and Ext JS, for each Ext JS event callback signature, Jangaroo Ext AS declares an event type class.

For example, in the Ext AS API of ext.button.Button, the onClick event is declared like so:

package ext.button {

[Event(name='onClick', type='ext.button.events.Button_eEvent')]
public class Button extends Component ... {
  ...
}

The event type class has an artificial name that is derived from its event source class and the event callback parameters. Fortunately, you don't have to use the class name when declaring event handlers in MXML (see below).

The Ext AS API defines the event type class for a button's click event like so (leaving out comments and some internals):

package ext.button.events {
import ext.button.Button;

import js.Event;

import net.jangaroo.ext.FlExtEvent;

public class Button_eEvent extends FlExtEvent {
  public static const CLICK:String = "onClick";
  public static const MOUSE_OUT:String = "onMouseOut";
  public static const MOUSE_OVER:String = "onMouseOver";

  public native function get source():Button;

  public native function get e():Event;
}
}

As you can see, the event type class defines constants for all event names that use this callback signature and "virtual" (native) properties for all callback parameters.

Now, a concrete button defined in MXML can implement a click event handler like this:

<Button xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns="exml:ext.config"
        text="Click me!"
        onClick="window.alert(event.source.text)"
/>

In MXML, event handler code is inserted as the event attribute's value directly, without curly braces. Similar to HTML, the code can be viewed as the body of a event handler function that receives an event parameter. In Flex, this parameter's type is derived from the corresponding [Event] annotation. This leads to a good IDE also knowing the type of the event identifier, so it gives you educated suggestions when code-completing event. and again for event.source. (which the event type class states to be of type Button).

Local References

To reference some instance created by an MXML object element, MXML allows to give it a local identifier through the id attribute. This identifier can only be used within the same MXML file. More technically speaking, an id attribute introduces a field of the given name that references the object instance created by that element.

This feature is often used in conjunction with event handlers. The event handler code might want to access another sibling component, like so:

<Container xmlns:fx="http://ns.adobe.com/mxml/2009"
           xmlns="exml:ext.config">
  <items>
    <DisplayField id="output" text="Click the Button!"/>
    <Button text="the Button"
            onClick=" output.text = 'Thank you!' "/>
  </items>
</Container>

By assigning the display field the local ID output, we can use this as an identifier referring to the display field instance in another component's event handler code. In this example, the text of the display field is changed when the button is clicked.

Clone this wiki locally