Skip to content
mohlendo edited this page Aug 30, 2011 · 20 revisions

Ext AS: Creating Ext JS Applications with ActionScript and EXML

Ext JS 3 is a JavaScript framework for building Rich Internet Applications (RIA). It is capable of building enterprise UI applications that run in the browser. However, using such a rich API from untyped JavaScript can be quite a pain.

Ext AS is the approach to combine Jangaroo’s enterprise JavaScript approach with the proven and rich Ext JS 3 framework. You write your application code in ActionScript, using an AS3 version of the Ext JS API, and translate it to JavaScript using Jangaroo tools. At runtime, the standard Ext JS code is invoked from your compiled code.

EXML

In addition to using ActionScript instead of JavaScript for the application code, Ext AS allows to write declarative components in an XML language called EXML. While Ext JS allows to use JavaScript object literals to specify components instead of assembling them in procedural code, Ext AS, like Flex, JavaFX, JSF, Silverlight and many others, uses XML, because it can be typed through an XML Schema. There are many tools providing development support for XML for which a Schema exists, so that you take advantage of features like code completion, documentation lookup, and verification. The Jangaroo EXML tool translates EXML into ActionScript, and then the Jangaroo AS3-to-JS compiler translates it to JavaScript. You can mix and match components written in ActionScript, EXML or JavaScript.

Getting Started

As for any Jangaroo development, you have to install Java 1.6 and Maven 3. If you have not done so, you find the according links and instructions in the Jangaroo Tutorial.

To give you a quick start, we have set up an Ext AS examples project on github. Please check out the latest release branch (currently with-jangaroo-0.8.6), since the master branch tends to use unreleased SNAPSHOT versions:

git clone git://github.com/CoreMedia/jangaroo-ext-as-examples.git -b with-jangaroo-0.8.6

If you are not familiar with cloning projects from github, you can simply download all files as zip by pressing the prominent “Downloads” button, select the latest link under “Download Packages” (currently jangaroo-0.8.6) and unzip the downloaded archive to a directory of your choice.

Building and Starting the Example

Since the examples project only contains the sources, you have to build the project before you can see anything running in the browser. An Ext AS application is built like any other Jangaroo application,
as described in the Jangaroo Tutorial, by opening a command shell in the project directory where the pom.xml is (here: hello-world-1-webapp) and typing mvn install. The build process should end with BUILD SUCCESSFUL.

Now, you can open the resulting HTML file target/hello-world-0.1-SNAPSHOT/index.html in any browser. The example shows a toolbar with a single button. When you click on the button, you see an awesome personalized greeting dialog.

Examining the Example

Let me give you a walk-through of the files in the example, with emphasis on what is specific for Ext AS applications compared to other Jangaroo applications. For general Jangaroo applications, regard the easy-to-follow Jangaroo Tutorial.

The example application hello-world-1-webapp contains all basic elements an Ext AS application requires:

  1. a Maven POM using the jangaroo-maven-plugin and with a dependency on ext-as
  2. an HTML wrapper src/main/webapp/index.html
  3. a class containing a static main() method, using the Ext AS API, here: src/main/joo/com/acme/extas/json/HelloWorld.as

hello-world-1-webapp is a simple application and does not use EXML. We’ll continue with EXML later in another example.

1. pom.xml

The key to developing Ext JS applications in ActionScript is a Jangaroo library called ext-as, which contains AS3 APIs for all Ext JS components and classes. All you need is add a dependency to that library in your pom.xml, like the one contained in every quick start example:

<project ...>
  ...
  <dependencies>
    <dependency>
      <groupId>net.jangaroo</groupId>
      <artifactId>ext-as</artifactId>
      <type>jangaroo</type>
      <version>0.8.10</version>
    </dependency>
  </dependencies>
</project>

Note that you should check for newer versions from time to time, best by following Jangaroo on Twitter or watching our Jangaroo Libraries Repository on github.

This dependency makes the Jangaroo Maven Build Process use the Ext AS API for reference during compile and copy all needed Ext JS artifacts into the resulting Web application.

2. src/main/webapp/index.html

When you know Jangaroo HTML wrapper or “bootstrap” files, there is not much special about this one. All you need to do is to include CSS of the desired Ext JS “theme” in the head of your HTML page. The file continues by loading jangaroo-application.js and starting the main() method of class com.acme.extas.json.HelloWorld.

3. src/main/joo/com/acme/extas/json/HelloWorld.as

The first HelloWorld class is very simple: it provides a static method main() that creates an Ext JS viewport, using a JSON configuration object. This example aims at showing that programming Ext JS in ActionScript need not be much different from using JavaScript directly. You’ll see the advantages of using ActionScript advanced language features such as typing and private members later, but for the first example, the important point is that ActionScript is a superset of JavaScript, so you can (almost) copy-paste JavaScript code into a main() method of an ActionScript class and it will work.

The differences are:

  • You need a package and a class declaration.
  • What is simply a function in JavaScript becomes a public static function in ActionScript.
  • We chose to follow ActionScript conventions and use lower case for package names. Thus, Ext.Viewport becomes ext.Viewport (however, both are the same object at runtime).
  • The argument of the Ext.Viewport constructor is an instance of ext.config.viewport, a so-called config class. Config classes provide typed getters and setters for all configuration options supported by an Ext AS component. They have been introduced to Ext AS to provide a clean separation of configuration API and runtime API. The name of a config class for a native Ext AS components always matches the name of the component class, but with a lower-case first character.
  • You have to import all referenced classes. The advantage is that you may use imported classes without package prefix (unless there is a name clash). The example code only uses fully qualified names to emphasize the similarity with how Ext is used in JavaScript. If you use several classes from the same package, you can use wildcard import (import ext.*).
  • To avoid too many global variables and functions, JavaScript symbols defined as global symbols in the browser must be accessed through the window object explicitly. For example, document.getElementById('foo') becomes window.document.getElementById('foo') and alert('bar') becomes window.alert('bar') (does not occur in the example code).

Custom Components in ActionScript

The second example, hello-world-2-as3, shows how to define a simple custom component, the class HelloWorld. This component inherits from ext.Viewport. It takes care of creating the nested components of the viewport and provides logic for reacting to events.

A config object that is created by the JavaScript fragment in the HTML file is passed to the main method and on the component constructor. During the component construction, Ext JS will apply the configuration object to the component, that is, it copies all attributes to the component object. This way, the user attribute is set, which can be accessed by a getter method.

This example takes the config class concept a little further. Instead of creating nested untyped configuration objects, instances of config classes like ext.config.button or ext.config.toolbar are created and configured using the defined attributes.

Custom Components in EXML

An obvious objection to the previous example would be that the nesting of the component classes is not readily apparent in the source code. This is fixed in example hello-world-3-exml. Here, the custom component is defined in EXML in the file HelloWorld.exml. Here the nested XML elements correlate to the nested components.

The basic structure of the EXML file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<exml:component xmlns:exml="http://www.jangaroo.net/exml/0.8"
                xmlns="exml:ext.config">
  <exml:import class="ext.MessageBox"/>
  ...
  <exml:cfg name="user" type="String">...</exml:cfg>
  <viewport>
    ..
  </viewport>
</exml:component>

The element <exml:component> indicates that this EXML file defines an EXT AS component. The nested elements <exml:import> reference ActionScript classes to be imported and used in embedded code. The elements <exml:cfg> defines configuration options supported by this component. All of these skeleton elements are placed in the XML namespace http://www.jangaroo.net/exml/0.8.

The only element in a different namespace below <exml:component> defines the base class from which the new component should inherit. In this case, it is viewport and the namespace URI exml:ext.config indicates that the config class with the name viewport is placed in the ActionScript package ext.config, like all components defined by Ext JS itself. Also, the name of the class is identical to the xtype as used by Ext JS.

Looking into the <viewport> elements, we see:

<viewport>
  <items>
    <panel title="Hello World!">
      ...
    </panel>
  </items>
</viewport>

The <items> element corresponds to the standard items property available in all Ext JS containers. All elements nested in the <items> element are parsed as component descriptions and added to the list of items, which is used when creating the view port. As you can see, the nesting of component class names and attribute names alternates as one descends the nested XML elements.

Attributes can also be specified as XML attributes of component elements. For example, the title attribute is set for the nested panel. Generally, the attributes are converted to the appropriate type based on the definition of the embedded components. In order to interpret an attribute value as ActionScript code, it has to be enclosed in braces like this:

<button
  text="Click me!"
  handler="{function(button:Button):void {
    MessageBox.alert(StringUtil.format('Hello {0}!', config.user),
                     StringUtil.format('{0} clicked on button \\'{1}\\'.', config.user, button.getText()));
  }}"/>

Here, an inline function for handling button events is defined. The next example will show how to get rid of this massive amount of code amidst a GUI declarations. However, short snippets of inline code can be quite useful at time. They are actually required to reference the config object, which carries all configuration attributes passed to the component at runtime.

During compilation, two ActionScript classes are generated from the EXML file: a component class and a config class. The package for the config class is configured in the file pom.xml, whereas the component class is placed in the same package as the EXML file. The compiler makes sure that the config class name starts with a lowercase character and that the component class name start with an uppercase characters. By convention, EXML file names start with an uppercase character.

The generated config class contains getters and setters for all configuration options. The generated component class merges the component configuration specified in the EXML file with the constructor’s config parameter.

As soon as the config class is accessed from ActionScript code, the component class is registered with the ext.ComponentMgr using the fully qualified of the config class as the xtype. Instances of the config class also carry that string in their field xtype, so that a config class instance can be passed to ext.ComponentMgr.create() for instantiation of the component.

Splitting Business Logic and UI

The module hello-world-4-as3-exml improves on the previous example by splitting procedural code and UI configuration. To this end, two ActionScript classes and one EXML file are provided. The class HelloWorldBase defines the method onClick, but does not take any interest in the UI setup, simply delegating to the constructor of Viewport. The config class helloWorldBase defines that the attribute user should be provided when instantiating the component. Finally, the EXML file HelloWorld.exml provides the UI definition, which is very similar to the previous example.

However, the button event handler is not defined inline, but referenced using the following definition:

<button text="Click me!" handler="{onClick}"/>

All inline code fragments are evaluated in the context of the component constructor. Therefore they do not only have got access to the config parameter, but also to the this reference to the component. Moreover, all members of the class definition are in scope, here the onClick function defined in the parent class.

Actions and Localization

The last example hello-world-5-localized shows how localization is handled in Ext AS applications. A set of property files according to the Java property file syntax is compiled into ActionScript classes, each property giving rise to a identically named getter function in the generated class. In the example, HelloWorld.properties is compiled to the class HelloWorld_properties. Language-specific property files override the default values from HelloWorld.properties.

The selected language is evaluated at class loading time, so that user code does not have to deal with selecting the correct locale. If the local should be changed, this can be achieved by calling ResourceBundleAwareClassLoader.INSTANCE.setLocale() and reloading the application afterwards, as shown in the action ChangeLocaleAction.

See the file HelloWorld.exml to see how actions can be configured using the config class changeLocaleAction associated with the action class. The EXML file also highlights how a method getBundle() of the base class can be used to access property value when localizing UI elements.

Clone this wiki locally