Ajaxify Your Flex Application

Flash applications embedded in web page containers usually run in isolation, with the web pages little more than dumb containers. This article will demonstrate how to leverage the ActionScript external interface to enable bidirectional communication between the two. Pay close attention so that you can complete the quiz at the end and be in the running to win a free copy of Adobe CS4 Web Premium and Flex Builder 3 Pro.

The term Rich Internet Application is still one of the current buzzwords of web development. Various vendors have thrown their hat into the ring and provided their own flavor of RIA development; it fails to surprise us that Adobe’s Flash Platform is one of the most interesting among those. The core element of the Flash Platform is obviously its virtual machine, also known as the Flash Player. The most common development technologies leveraging that runtime are Adobe’s Flash Authoring Environment, Flex Builder, and the open source Flex SDK – both the latter comprising the Flex framework.

Flash and Flex are very cool technologies – particularly when you look outside the boundaries of the browser and think about running your Flash-based RIAs in AIR on the user’s desktop. Yet the Flash platform is only one technology people nowadays use out there in the wonderful world of the Web, so, in this tutorial, we’re going to look at some of the different ways a Flex-based application running in the Flash Player can communicate with the outside world.

Technical Requirements

A lot of the content we’re covering here is valid for both Flash and Flex, because we’re actually talking about the features and API of the Flash Player. All the examples in this tutorial use Flex 3, so you might want to start running either the open source Flex 3 SDK or Flex Builder 3.

From here on I’ll use the term Flex application as a synonym for an .swf file-based application created with either Flash or Flex. It should be fairly simple for you to transfer the information provided here into using the Flash Authoring environment. If you wish to explore this further, you’d benefit from using Flash CS3 or CS4. From a Flash Player point of view, the example code should work fine in Flash Player versions 9 and 10.

In general, an .swf-based application in combination with the Flash Player is executed in an environment known as a "container application." Let’s start by having a closer look at the most common environment for your Flex application: a web page container (sometimes called "HTML wrapper"). Besides using the common web page container environment, the Flash Player offers some other deployment options; I’ll provide a few references for following these up towards the end of the tutorial.

The HTML Wrapper

Most readers will probably be familiar with the structure of a web page and the general concepts of embedding Flex applications in such an environment. However, it can become a bit tricky when you start trying to ensure that your Flex application works in every browser, and triggering an automated update of the user’s Flash Player if necessary. Applications that have been created with Flash CS 3 and 4, and Flex 2 and 3 need to be executed in a Flash Player of at least version 9. (This is so your application can use the new virtual machine and properly support ActionScript 3, as well as a few other cool things).

The easiest way to start is to use an established template that already has code to properly embed a Flex application into your web page. A Flex Builder 3 project comes with an HTML template, providing a good starting point. The image below shows the folder structure of such a project. The folder html-template holds template files that are customized and populated with your project settings for the HTML environment on compilation of your Flex application; the resulting compiled files are located in the folder bin-debug. It’s important to understand that any changes made to files in bin-debug are overwritten when you recompile your project; therefore, changes should only be made to files in the html-template folder.

A Flex Builder project folder structure

Keeping that in mind, I’d like to explain the most important parts of a HTML wrapper. Basically the HTML wrapper page uses a JavaScript library (AC_OETags.js, imported at the top of the page) to find out which version of the Flash Player is actually available on the browser client. It will then, depending on the results, either execute the Flex application or initiate a smart upgrade of the Flash Player. However, if the Flash Player has yet to be installed or the available Flash Player is older than version 6.0.65, the JavaScript library will then display alternative HTML content. Further down on the HTML page, you’ll additionally find a <noscript> section with <object> and <embed> tags; this will be executed if JavaScript is unavailable, or disabled on a client.

Let’s take a closer look at the call to the AC_FL_RunContent function and the <object> tag that appears further down:

AC_FL_RunContent( 
 "src", "FlexAndJS",
 "width", "100%",
 "height", "100%",
 "align", "middle",
 "id", "FlexAndJS",
 "quality", "high",
 "bgcolor", "#869ca7",
 "name", "FlexAndJS",
 "allowScriptAccess","sameDomain",
 "type", "application/x-shockwave-flash",
 "pluginspage", "http://www.adobe.com/go/getflashplayer"
);
...
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
   id="FlexAndJS" width="100%" height="100%"
   codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
 <param name="movie" value="FlexAndJS.swf" />
 <param name="quality" value="high" />
 <param name="bgcolor" value="#869ca7" />
 <param name="allowScriptAccess" value="sameDomain" />
 <embed src="FlexAndJS.swf" quality="high" bgcolor="#869ca7"
     width="100%" height="100%" name="FlexAndJS" align="middle"
     play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
     type="application/x-shockwave-flash"
     pluginspage="http://www.adobe.com/go/getflashplayer">
 </embed>
</object>
Passing Data into a Flex Application Using FlashVars

Let’s return to the original topic of this tutorial. We wanted to make our Flex application communicate with the HTML wrapper. The easiest way to do so is to use an approach called FlashVars. FlashVars is a very similar concept to sending data as HTTP GET parameters from page to page; effectively we’re passing key/value-pairs of data to the Flex application.

To do so, we need to add a FlashVars attribute to our two locations in the HTML. The value of the FlashVars attribute would be a URL-encoded list of parameter pairs, as in: name=kai&site=ventego-creative.co.nz&... and so on. Embedding this into the code example from above will achieve the following result:

AC_FL_RunContent( 
 "src", "FlexAndJS",
 ...
 "FlashVars", "name=kai&site=ventego-creative.co.nz");
...
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
   id="FlexAndJS" width="100%" height="100%"
   codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
 <param name="movie" value="FlexAndJS.swf" />
 ...
 <param name="FlashVars" value="name=kai&site=ventego-creative.co.nz" />

 <embed src="FlexAndJS.swf" quality="high" bgcolor="#869ca7"
     ...
     FlashVars="name=kai&site=ventego-creative.co.nz">
 </embed>
</object>
FlashVars data can be easily used in the Flex application by referring to the parameters object in Application.application. For example, to retrieve the content of the variable site that has been passed in via FlashVars, you'd use a snippet similar to the example below in the ActionScript part of your Flex application:

public var theSite:String = Application.application.parameters.site;

Obviously this means of communication between the wrapper and the Flex application is quite inflexible (you're limited to serialized, flat data in key/value-pairs) and fails to provide a two-way communication. Still, FlashVars are quite often used when the application requires (non-critical) data to be passed in at start time.

ExternalInterface

Now we need to introduce a truly bidirectional communication channel between the Flex application and its wrapper: Flash Player's external API, also known as ExternalInterface. The ExternalInterface class is the representation of the external API in ActionScript 3. In earlier versions of Flash (up to version 8) the fscommand function was used to provide access to the external API.

It can be applied in the following use-cases:

  • retrieve information about the Flex application's container
  • call and execute code in the container from ActionScript in Flex
  • call and execute ActionScript code in the Flex application from the container

The external API is a subsystem of the Flash Player that's being leveraged in ActionScript 3. When I mentioned "call and execute code in the container" in the list above, I was actually referring to executing JavaScript code in our HTML wrapper page. We will therefore introduce a way to set up and run bidirectional function calls from HTML and JavaScript to Flex and ActionScript.

Before I show you some code, let's talk about stuff that's good to know:

  1. First, some bad news: you may sometimes struggle to have access to the ExternalInterface class. The good news is, though, that you rarely run into issues regarding the availability of the ExternalInterface on most of the modern browsers. You'll be fine if the client browser is one of either:

    • Internet Explorer 5+ on Windows
    • a browser supporting the NPRuntime interface (for example, Firefox 1+, Safari 1.3+, Netscape 8+, Opera 9+)

    The recommended way to check the availability of the external interface is to test the value of ExternalInterface.available; it will return true if available. This result actually neglects telling you about the status of the browser's JavaScript settings (that is, whether the user's JavaScript is enabled); it will only inform you that conceptually your application could leverage the external API.

    Keeping that in mind, you should apply the following generic structure to your external API calls in ActionScript:

    if(ExternalInterface.available)  
    {  
     // Execute ExternalInterface calls in here.  
    }

  2. If the HTML tags (the resulting <object> and <embed> tags) are nested in a HTML form, ExternalInterface calls from Flex and ActionScript to JavaScript in the HTML wrapper will fail to work.

  3. In Internet Explorer, if the <object> tag's id attribute contains a character that can be interpreted as a JavaScript operator (for example, -) Flex/ActionScript calls to the wrapper will function incorrectly.

Calling JavaScript Code from Flex

I'll demonstrate the first use-case I mentioned previously: retrieving container information. Let's have a look at a Flex application using the ExternalInterface class to display the navigator.userAgent property of its surrounding container:

<?xml version="1.0" encoding="utf-8"?>  
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" verticalAlign="middle" creationComplete="init();">  
 
 <mx:Script>  
   <![CDATA[  
     import mx.controls.Alert;  
 
     private function init():void  
     {  
       if (ExternalInterface.available)  
       {  
         var userAgent:String = ExternalInterface.call(  
             "navigator.userAgent.toString");  
          Alert.show(userAgent, "UserAgent information:");  
        }  
      }  
    ]]>  
  </mx:Script>  
 
 <mx:Button label="display user agent (again)" click="init();" />  
 
</mx:Application>

The simple logic is encapsulated in the init function, and we can see that ExternalInterface.call actually executes the call to the HTML wrapper. In this case we're simply calling the toString function for the navigator.userAgent property.

Let's take the next step: what if we had some JavaScript code on the page that we would want to execute from within our Flex application? Actually, it's fairly straightforward, with the call method of the ExternalInterface class again doing the job for us:

...  
<mx:Script>  
 <![CDATA[  
   private function callJavaScript():void  
   {  
     ExternalInterface.call("sayHelloWorld");  
   }  
 ]]>  
</mx:Script>  
...

In this instance, we're providing call with the name of the JavaScript function we wish to execute. The corresponding JavaScript function obviously has to be included in the wrapper; in the following example, we're basically triggering the display of a JavaScript alert popup from within the Flash Player. Here's the JavaScript:

<script type="text/javascript">  
 function sayHelloWorld()  
 {  
   alert("Hello World from JavaScript");  
 }  
</script>

Passing arguments from ActionScript to a JavaScript function via the ExternalInterface class follows a very similar syntax. The arguments are passed into the call method as additional parameters:

...  
<mx:Script>  
 <![CDATA[  
   private function callJavaScript():void  
   {      var a:int = 4;  
     var b:int = 4711;  
     var calcResult:int =  
         ExternalInterface.call("doCalculation",a,b);  
   }  
 ]]>  
</mx:Script>  
...

The JavaScript function might appear as below:

<script type="text/javascript">  
 function doCalculation(number1, number2)  
 {  
   return number1 * number2;  
 }  
</script>

Be aware that if the call to JavaScript fails or your JavaScript function is without an appropriate return value, the result of the ExternalInterface call would be null.

If you're dealing with security sandboxes in the Flash Player, you might experience SecurityError exceptions. There are two things you could do to avoid trouble during development, as well as when moving from development to testing and production:

  1. Set an appropriate value of the allowScriptAccess attribute in the <object> and <embed> tags of your HTML page.
  2. Develop in a realistic environment - build and test your applications in pages delivered to your browser from a (local) HTTP server such as Apache or IIS via the http:// protocol, instead of using the file:// protocol prefix in your browser.

What's good about using the external API is that it allows us to use most plain data types, and also some complex types like Arrays.

Calling ActionScript Code from HTML and JavaScript

As I've indicated before, ExternalInterface offers a bidirectional communication channel. Therefore, we're able to call ActionScript code in the Flex application from JavaScript code embedded into the HTML wrapper. This process turns out to be a bit more complex than the other way around, because we actually will have to set up some callback handlers.

Let's again experiment with displaying alert popups. This time we want to use a HTML button as a trigger for displaying an alert window in the Flex application, which itself displays the current date and time. The first step is the callback, because we need to tell the Flex application which ActionScript method to run if a particular signal is being sent from the wrapper. The callback is created in the Flex application's init method:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" ... creationComplete="init();" ...>  
 
 <mx:Script>  
   <![CDATA[  
     import mx.controls.Alert;  
     private var alert:Alert;  
 
     private function init():void  
     {  
       ExternalInterface.addCallback("showAlert", showAlert);  
     }  
 
     private function showAlert(msg:String):void  
     {  
       var now:Date = new Date();  
       alert = Alert.show(msg,now.toLocaleDateString());  
       alert.status = now.toLocaleTimeString();  
     }  
 ]]>  
</mx:Script>  
 
</mx:Application>

Our use of the addCallBack method above exposes a function name that can be called by JavaScript, "showAlert"; that will then call the ActionScript method showAlert.

On the HTML page we define the function that will be executed with the click of a button, asAlert, and one other helper function needed to obtain a reference to the Flash movie object, thisMovie:

<script type="text/javascript">  
 function thisMovie(movieName)  
 {  
   if (navigator.appName.indexOf("Microsoft") != -1)  
   {  
     return window[movieName];  
   }  
   else  
   {  
     return document[movieName];  
   }  
 }  
 
 function asAlert(value)  
 {  
   thisMovie("alertFromFlex").showAlert(value);  
 }  
</script>

As you can see, the function asAlert leverages the helper function thisMovie to return a reference to the HTML DOM element containing our Flash movie, and calls its showAlert method, passing in a string value.

To make the code above work properly, you'd need to ensure this: the argument being passed into the thisMovie function (here "alertFromFlex") needs to be identical to the id attribute of the <object> tag, as well as the name attribute of the <embed> tag being used to embed your Flex application in the page.

Please be aware of one potential issue you could run into when using JavaScript to communicate with the Flex application: it's hard to predict the exact point in time during page rendering that the Flex application will be available. Therefore, it might be a good idea to set a flag named jsReady to true using the onload event of the browser window that could be queried from ActionScript. If the value of the flag is true, we can safely assume the page load has been complete and we can set up the callback handlers in ActionScript.

Where Next?

While this article should help start you off, there are plenty of other possibilities for the Flash Player's external API. Examples are unlimited, and could include complex form elements and controls built in Flex that have to be embedded into existing HTML forms; image upload controls and management systems in Flex that have to interact with the surrounding HTML page; or hooking your Flex application into existing third party JavaScript APIs.

In the article, I mentioned the possibility of having a non-HTML page wrapper. Usually this would be the Flash Player ActiveX control, embedded in a stand-alone application developed in other technologies. Adobe provides some basic information on how to approach such an undertaking with C# and .NET. A highly recommended tutorial on embedding the ActiveX control into your own applications can be found on richapps.de.

Also, if you're serious about linking Flex and JavaScript, make sure you have a further look into a library called Flex/AJAX Bridge. The name is slightly misleading, as it's really a library to make the communication between both technologies easier, with barely a focus on Ajax. It basically abstracts the underlying ExternalInterface calls, and gives you easy access to passing even complex objects - such as references to UI components - between Flex and the wrapper. Only a small amount of people know about the existence of this tool kit, but it comes with the Flex SDK and Flex Builder. You'll find it in the folder frameworks/javascript/fabridge.

Test Your Knowledge

Remember all that? Test yourself on the contents of this article by doing the quiz. Submit your answers for a chance to win a free copy of Adobe CS4 Web Premium and Flex Builder 3 Pro. Take the quiz now!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.