MXML is a declarative markup language used to create the user interface and to view portions of Flex applications. As the name implies, MXML is an XML-based language. If you’re familiar with XML or even HTML, many of the basic MXML concepts we discuss in this chapter will already be familiar to you in a general sense. In this chapter, we’ll look at all the basics of working with MXML, including the syntax and structure of the language, the elements of which MXML is composed, creating interactivity in MXML, and how you can use MXML to build applications.
If you’ve ever worked with XML or HTML, the structure of MXML will be familiar to you. Even if XML and HTML are unfamiliar to you, you will likely find MXML fairly intuitive. MXML uses tags to create components such as user interface controls (buttons, menus, etc.), and to specify how those components interact with one another and with the rest of the application, including data sources. In the following sections we’ll look at how to write MXML code.
All MXML must appear within MXML documents, which are plain-text documents. You can use any text editor, XML editor, or IDE that can work with text or XML to write MXML, including those listed in the preceding chapter. To create a new MXML document, you can create a new text file with the .mxml file extension. If you are using Flex Builder, you can use the program’s menus to add either a new MXML application, MXML module, or MXML component. All are MXML documents, differing only in the root element added to the document (as you’ll see in this chapter).
Every document can and should have an XML declaration. Many IDEs and XML editors automatically add an XML declaration. Flex Builder adds an XML declaration by default using UTF-8 as the encoding. You must place the declaration as the first line of code in the MXML document, and unless you have a compelling reason to use a different encoding, you should use UTF-8 for the best compatibility:
<?xml version="1.0" encoding="utf-8"?>
Note that an XML declaration is not strictly required by the Flex compilers. However, for well-formed MXML, you should always include the XML declaration as it is recommended by the XML 1.0 specification.
All MXML documents can have just one root node. There are three types of MXML documents, and they are
defined by the type of root node they have. The first type of MXML
document is an application document. Application documents use Application
nodes
as the root node. All Flex applications must have one application
document, and application documents are the only type of document you
can compile into a Flex application. The following is an example of a
basic application document that Flex Builder creates by
default:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> </mx:Application>
Note that the layout
attribute is not strictly required, but it is shown here because
this is the default tag Flex Builder creates.
There are a few items to notice about this example:
The Application
node has
matching opening and closing tags. The closing tag is prefixed by
a forward slash (/
). All MXML
nodes must be closed as in any well-formed XML.
The tag name uses an mx
namespace. You can identify a namespace in a tag because the tag
name is prefixed with the namespace identifier followed by a
colon. We’ll talk more about namespaces in the next
section.
The Application
tag in
this example has two attributes, called xmlns
and layout
. You use attributes to set values
for a node. In this case, the xmlns
attribute defines the mx
namespace prefix (more about this in
the next section), and the layout
attribute defines the way in
which the contents of the document will be positioned. The
layout
attribute is optional
(we discuss this attribute in more detail in Chapter 6). For now, you
can define application documents with an absolute layout or with
no explicit layout attribute value. We’ll talk more about
attributes in Setting component properties”
later in this chapter.
Component documents are used to define MXML
components, which are encapsulated elements of your
application that you can abstract and isolate into their own documents
to make your applications more manageable. We’ll talk more about
custom components in Chapter 9, and
Chapter 19. The structure of
component documents is similar to that of application documents in all
respects except that the root node is not an Application
tag. Rather, a component
document uses an existing component as the root node (which is the
superclass for the new MXML document/class). Again, we’ll discuss this
in much more detail later in this chapter and later in the book.
However, for illustrative purposes, here we’ll look at a simple
example of a component document that is based on a standard Flex
framework component called Canvas
:
<?xml version="1.0" encoding="utf-8"?> <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"> </mx:Canvas>
While the preceding is a complete component document, you can't compile an application from it. All Flex applications require an application document in order to compile, and you can use instances of component documents within the application document. You’ll learn more about how to create custom components and use them in a Flex application in Chapter 9.
As you can see in this example, the structure of the document is
much the same as that of the application document, but with a
difference: the root node is a Canvas
tag rather than an Application
tag.
A module document is also remarkably similar to application and
component documents, the primary difference being the root tag. A
module document is used to define an MXML module, which you’ll learn
more about in Chapter 9. The root tag
for a module document is Module
as
in the following example:
<?xml version="1.0" encoding="utf-8"?> <mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"> </mx:Module>
All other MXML code appears within the root node of a document. For example, if you want to add a button to an application, the document might look like this:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Button label="Example Button"></mx:Button> </mx:Application>
Although we haven’t yet discussed the button component,
you can see quite clearly that the tag that adds the
component is nested within the opening and closing tags of the root
node. You’ll also see that the syntax for the tag that adds the button
is similar to that of the Application
tag. It uses <
and >
characters to demarcate the tag, and it
uses the same syntax for attributes. The Button
tag in this example also has an
opening and closing tag. If you omitted the closing tag, the compiler
would not be able to compile the application. However, in the case of
the button component, you would not typically nest any tags within it.
Therefore, it is sometimes convenient to be able to open and close a
node with just one tag. There is a shortcut to achieve this goal. You can
simply add a forward slash immediately prior to the >
character of the opening tag. That
means you can rewrite the preceding example in the following
way:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Button label="Example Button" />
</mx:Application>
That covers the fundamentals of MXML structure. We’ll be elaborating on how to work with specific components and specialized tags throughout the remainder of the book.
As shown in the preceding section, MXML uses something called a namespace. Simply put, a namespace is a unique grouping for elements—in this case Flex libraries. The entire Flex framework is written in ActionScript classes and a few MXML component documents that are stored in external libraries within .swc files. These external libraries contain tens if not hundreds of classes (and MXML components). Using these elements from ActionScript is not difficult. However, to use the elements from MXML you have to be able to map the library classes and MXML components to tags. You do this through manifest files and namespaces.
As shown in Chapter 2, a manifest file
maps an ActionScript class to an identifier: the MXML tag
name. A manifest file in and of itself would be enough to
enable access to ActionScript classes and MXML components by way of
MXML tags. However, the difficulty is that you need a way to ensure
uniqueness of scope for the mappings. For example, the Flex framework
defines a mapping called Button
that points to a class called mx.controls.Button
—a component that creates
a simple user interface button. Yet what if you wanted to create your
own class that maps to a Button
identifier? This poses a problem because you cannot meaningfully have
two Button
identifiers within the
same scope. If you did, how would the application know which button
you are referencing? This highlights the utility of namespaces.
A namespace allows you to create a unique uniform resource
identifier (URI) that corresponds to a particular manifest
document. This namespace URI is set when the .swc file is compiled, as described in
Chapter 2. You may
recognize this particular URI from the MXML examples shown in the
previous section. Within the MXML document you must tell Flex which
namespaces you want the document to use. You can do that using the
xmlns
attribute. If you use the xmlns
attribute by itself, it defines the default namespace for the
document. Therefore, the example that follows on the next page is a
valid MXML application document that adds a button component.
<?xml version="1.0" encoding="utf-8"?> <Application xmlns="http://www.adobe.com/2006/mxml" layout="absolute"> <Button label="Example Button" /> </Application>
This example says to use the Flex framework namespace as the default namespace for the document. This means
that every tag used in the document is assumed to correspond to one of
the mappings in the Flex framework manifest file. Therefore, the
Application
tag maps to the class
that corresponds to the Application
identifier in the manifest file. This is perfectly valid. However,
this is not the way in which MXML documents typically utilize the Flex
framework namespace; an MXML document may contain tags that shouldn’t
map to the Flex framework namespace by default. Therefore, it is
better not to define that namespace as the default, but rather to use
a namespace prefix. By convention we use the mx
prefix for the Flex framework namespace.
You can use a namespace prefix by following xmlns
with a colon and the prefix before
assigning the value, as in the following example:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Button label="Example Button" /> </mx:Application>
This example, which is exactly the same as an earlier example,
adds the mx
prefix for the Flex
framework namespace. That means you must then prefix all tags that are
part of that namespace with the mx
prefix (e.g., <mx:Button>
).
By using namespace prefixes, you can create additional namespaces and utilize them within Flex applications. Each namespace can use a different prefix within the MXML document, ensuring that even if two namespaces use the same mapping identifiers, they will not be in conflict. The following example illustrates this:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:example="http://www.example.com" layout="absolute"> <mx:Button label="Example Button" /> <example:Button /> </mx:Application>
This example presupposes that a valid external library is
already compiled with the namespace URI of http://www.example.com and that the library’s manifest
file contains a mapping identifier of Button
. In this example, the application
creates one button from the Flex framework and one button from the
example library. We’ll see more examples of creating custom namespaces
for custom libraries in Chapter 20. Although no rule
states that you must use the mx
prefix for the Flex framework namespace, it is the standard
convention, and we use that convention in this book.
Flex applications are largely composed of components, or modular elements. Technically, a component is an ActionScript class or an MXML component document that you can instantiate in an application. In some cases the class or component document has been mapped to an identifier via a manifest file, and in some cases you can merely reference the class or component document by way of the fully qualified name. There are many different types of components, but in terms of the Flex framework components, there are two basic categories: visual and non-visual. The visual components consist of the following:
Containers
User interface controls
The non-visual components consist of the following:
Data components
Utility components
Containers are types of components that can contain other
components. Every application must use containers. At a minimum, the
Application
element itself is a
container because you can place other components within it. You use
containers for layout. There are containers for vertical layout, horizontal layout,
grids, tiles, and all sorts of layout configurations. When you use
layout containers, you place other components within them using nested
tags. The following uses a VBox
(a
container that automatically arranges the child elements so that they
are stacked vertically) to stack two buttons:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:VBox> <mx:Button label="Example Button 1" /> <mx:Button label="Example Button 2" /> </mx:VBox> </mx:Application>
You can nest containers within containers, as the following
example shows, by placing an HBox
(a container
that automatically arranges the child elements so that they are placed
side by side horizontally) inside a VBox
:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:VBox> <mx:Button label="Example Button 1" /> <mx:Button label="Example Button 2" /> <mx:HBox> <mx:Button label="Example Button 3" /> <mx:Button label="Example Button 4" /> </mx:HBox> </mx:VBox> </mx:Application>
You can read more about layout containers in Chapter 6.
User interface controls are visible interface elements such as buttons, text inputs, lists, and data grids. There are many types of UI controls, and we discuss them in more detail in Chapter 7. You’ve already had a chance to see several examples with a button control.
When you work with components, you often need to configure them
by setting properties. For example, a button
component lets you apply a label by setting a property. Every
component type has its own unique set of properties that you can set.
For example, a button
and a
VBox
clearly have different
properties because they do different things. However, despite the
difference in the specific properties available for components, you
can set the properties using the same techniques. You can set
properties of components in several ways:
The simplest and most common way to set properties for a
component is to use the tag attributes. We already showed several examples of this technique in
earlier code examples. For instance, the Application
tag allows you to set a layout
property using a tag attribute, as in
the following example:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> </mx:Application>
You’ll notice that tag attributes always appear in the opening tag following the tag name. A tag can have many attributes, each separated by spaces. The attributes themselves consist of the attribute name, an equals sign, and the value enclosed in quotation marks.
Almost all components (all visible components) have an id
property. In most instances of containers and UI controls, you
should set the id
property, because
that is how to reference the instance using data binding or
ActionScript. The id
property is
the name of the component instance, and it must be unique within the
document. The value must also follow a few naming rules. Specifically,
the id
property for a component
should consist only of letters, numbers, and underscores, and it
should start with either an underscore or a letter, but not a number.
The following assigns an id
value
to a button:
<mx:Button id="exampleButton" label="Example Button" />
You can set most properties (though not the id
property) using nested tags as an
alternative to tag attributes. The nested tags use the same name as
the property/attribute, but they must be prefixed with the correct
namespace prefix.
The following example assigns a button label using a nested tag:
<mx:Button id="exampleButton"> <mx:label>Example Button</mx:label> </mx:Button>
In most cases, it’s preferable to set properties using
attributes rather than nested tags because attributes are a more
compact and more readable format. However, there are legitimate use
cases that justify using nested tags. For example, some properties
require complex values that cannot be represented by a string value
placed within quotation marks. One such example is the dataProvider
property for a combo box (a drop-down menu component). The
dataProvider
property of a combo
box must be some sort of collection of values. The following example
creates a combo box and uses a nested dataProvider
tag to populate it with
values:
<mx:ComboBox id="exampleComboBox"> <mx:dataProvider> <mx:ArrayCollection> <mx:Array> <mx:String>A</mx:String> <mx:String>B</mx:String> <mx:String>C</mx:String> <mx:String>D</mx:String> </mx:Array> </mx:ArrayCollection> </mx:dataProvider> </mx:ComboBox>
Note that you can also set the dataProvider
property using ActionScript,
which would not require nested tags. However, when you want to use
MXML to set the dataProvider
property, you must use nested tags, as in this example.
You can also set properties using ActionScript. When you set an
id
property for a component, you
can reference it using that name as an ActionScript object. Most
(though not all) component properties have the same names as
attributes and as ActionScript
properties. We’ll look at working with ActionScript in the next
chapter.
As mentioned earlier, there are two types of non-visual components: data components and utility components. Data components are used to create data structures, such as arrays and collections, and for making remote procedure calls with protocols like SOAP for web services or AMF for Flash Remoting. You can read more about data components in Chapter 17.
Utility components are components used to achieve functionality. Examples of utility components are those used for creating repeating components and for creating data binding between components. Since utility components are responsible for varied, generally unrelated tasks, we haven’t grouped them all in one chapter. Rather, you’ll find discussions of utility components in the context of the topics when you’d most likely use the components. For example, the data binding component is discussed in Chapter 14, and the repeater component is discussed in Chapter 6.