Note: This article was created based on the Flex 3 beta releases. Minor changes in the description and code may be necessary before it can be applied to Flex 3.
When building web applications or websites, you will encounter many instances in which JavaScript is needed and used. These are usually in rich Internet applications (RIAs) that are built using many different techniques. One great example of an RIA that has many different components is Google Finance. In the Google Finance site, you will notice that HTML, CSS, JavaScript, and Flash all work together to make a seamless user interaction. But what you don't see is the glue that holds these together; and that is what this article is going to talk about and show. This article goes into detail about communicating between Flex and JavaScript using the ExternalInterface API. So sit back and enjoy this tutorial as it explains the basics of creating these multiple component web applications using JavaScript as the glue that holds them together.
In order to make the most of this article, you need the following software and files:
To understand and make use of this tutorial, you should have built simple Flex applications before, and have a basic understanding of HTML and JavaScript.
The application shown here gives you a little taste of what can be done between JavaScript and Flex. You can add people to the Flex application using the small form on the bottom right through JavaScript, and if you select a person in the Flex app and click the "JavaScript Display" button, you will get the info back out to the small form on the top right.
<style type="text/css">
table.sample {
width: 225px;
border-width: 1px;
border-spacing: 2px;
border-style: dotted;
border-color: gray;
border-collapse: collapse;
background-color: white;
}
table.sample td {
font-size: 9px;
border-width: 1px;
padding: 5px;
border-style: dotted;
border-color: gray;
-moz-border-radius: 0px 0px 0px 0px;
text-align: left;
}
</style>
<script language="javascript">
// Internet Explorer and Mozilla-based browsers refer to the Flash application
// object differently.
// This function returns the appropriate reference, depending on the browser.
function getFlexApp(appName) {
if (navigator.appName.indexOf ("Microsoft") !=-1) {
return window[appName];
} else {
return document[appName];
}
}
function displayPerson(person)
{
if(person == null){
alert("Please select a person, or maybe I screwed
up.");
}
else{
document.getElementById('nameDisplay').innerHTML = person.Name;
document.getElementById('ageDisplay').innerHTML = person.Age;
document.getElementById('sexDisplay').innerHTML = person.Sex;
}
}
function addPerson()
{
var name = document.getElementById('txtName').value;
var age = document.getElementById('txtAge').value;
var sex = document.getElementById('selSex').value;
getFlexApp('FlexJSTutorial').addPerson(name, age, sex);
}
</script>
<center>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="FlexJSTutorial" width="482" height="348"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="http://blog.paranoidferret.com/files/JSTutorial.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="always" />
<embed src="http://blog.paranoidferret.com/files/JSTutorial.swf"
quality="high" bgcolor="#869ca7" width="482" height="348"
name="FlexJSTutorial" align="middle"
play="true"
loop="false"
quality="high"
allowScriptAccess="always"
type="application/x-shockwave-flash"
pluginspage="/go/getflashplayer">
</embed>
</object>
<br><br>
<table class="sample">
<tr><td style="font-size:
11px;font-weight:bold;text-align: center;border-width: 1px;padding:
3px;border-style: dotted;border-color: gray;-moz-border-radius: 0px 0px 0px
0px;">Data coming into Javascript</td></tr>
<tr><td>
<table width="100%"
style="border-spacing:5px;">
<tr><td>Name:</td><td
id="nameDisplay"
style="width:150px;"> </td></tr>
<tr><td>Age:</td><td
id="ageDisplay"
style="width:150px;"> </td></tr>
<tr><td>Sex:</td><td
id="sexDisplay"
style="width:150px;"> </td></tr>
</table>
</td></tr>
<tr><td style="font-size:
11px;font-weight:bold;text-align: center;border-width: 1px;padding:
3px;border-style: dotted;border-color: gray;
-moz-border-radius: 0px 0px 0px 0px;">
Data sending from Javascript
</td></tr>
<tr><td>
<table style="border-spacing:5px;" width="100%">
<tr><td style="border-style:none;padding:0px;">Name:</td>
<td style="border-style:none;padding:0px;"><input
id="txtName" type="text" /></td></tr>
<tr><td style="border-style:none;padding:0px;">Age:</td><td
style="border-style:none;padding:0px;"><input
id="txtAge" type="text" /></td></tr>
<tr><td style="border-style:none;padding:0px;">Sex:</td>
<td style="border-style:none;padding:0px;"><select
id="selSex" style="width:100px;"><option
value="Male">Male</option><option
value="Female">Female</option></select></td>
</tr>
<tr><td colspan="2" style="border-style:none;padding:0px;"><input
type="button" id="butAddPerson" onclick="addPerson()" value="Add Person"
/></td></tr>
</table>
</td></tr>
</tbody>
</table>
</center>
The very first thing to do is to set up a basic Flex
application; the code below represents the closest to the simplest interface
possible. This sets up an application with specified height and width and also
adds the View Source option to the movie, with the source file specified by the viewSourceURL attribute.
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="482" height="348" viewSourceURL="../files/JSTutorial.mxml"> </mx:Application>
The next step in the process is to set up a simple Flex
interface with no functionality built in. You now add a panel into the application
and give it a title. Next you add a DataGrid object that will be bound to the
datam which will be defined later. In the DataGrid you add a couple of columns
(DataGridColumn); take notice to the dataField names, as they
will define the keys for the incoming data. So in this case, the data coming in
should have values from three keys: "Name", "Age" and "Sex".
You will also add a button, which will later be used to call a JavaScript
function on the page. Lastly you will add a label to give yourself a quick
status update when sending the data to JavaScript. You also give each of the UI
components an id attribute so that you can refer to them later. All this
code goes inside the <mx:Application> tags.
<mx:Panel id="pnlMain" x="10" y="10" width="462" height="328" layout="absolute" title="Simple Javascript Interaction"> <mx:DataGrid id="dgPeople" x="10" y="10" width="422" height="229"> <mx:columns> <mx:DataGridColumn headerText="Name" dataField="Name"/> <mx:DataGridColumn headerText="Age" dataField="Age"/> <mx:DataGridColumn headerText="Sex" dataField="Sex"/> </mx:columns> </mx:DataGrid> <mx:Button x="10" y="256" label="JavaScript Display" id="butJSDisplay" /> <mx:Label x="149" y="260" id="lblMessage"/> </mx:Panel>
At this point you should be able to compile and run the app to see your small interface.
Next, you need to get some data into your DataGrid, and you
are going to do this with a small bit of ActionScript 3.0 . First, you attach a
function call to the DataGrid's initialize event. So your new DataGrid
opening tag looks like this:
<mx:DataGrid id="dgPeople" x="10" y="10" initialize="initDG()" width="422" height="229">
Now, to go along with the event, you need to write the
actual function to which it refers. The first thing you need to do is add a <mx:Script> tag to the application; then, you can start writing the function. You can also
add an import call so that you can use ArrayCollection.
Inside the function initDG you do a little bit of data creation. You create an array for the data, and
then push a few items onto the array. You can use the {key1: "value1", key2: "value2"...} syntax to add an associative array for each item. Next you need to make sure
the keys match the ones you used for the DataGridColumns so that the DataGrid
knows what columns to associate with what values. Once that's done, you need to
create an ArrayCollection to bind to and stick the array in it. And the last
thing you do is bind the dgPeople (DataGrid) to the ArrayCollection and set the initial selected index. So, this
gives you the following code for the script, and this code goes right below the <mx:Application> opening tag.
<mx:Script> <![CDATA[ import mx.collections.ArrayCollection; public function initDG():void { var people:Array = new Array(); people.push({Name: "Charlie", Age: "23", Sex: "Male"}); people.push({Name: "Brandon", Age: "23", Sex: "Male"}); people.push({Name: "Mike", Age: "23", Sex: "Male"}); people.push({Name: "Caroline", Age: "23", Sex: "Female"}); var peopleCollection:ArrayCollection = new ArrayCollection(people); dgPeople.dataProvider = peopleCollection dgPeople.selectedIndex = 0; } ]]> </mx:Script>
Okay, you again should be able to compile and run the application, and now there should be data in your DataGrid.
Next up is sending this data to JavaScript. This is pretty
easy to do. To start off, you need to add a click event to the
button to call an ActionScript function. Below is the new modified button tag.
<mx:Button x="10" y="256" label="JavaScript Display" id="butJSDisplay" click="jsDisplayPerson()"/>
Now, to make this button work, you need to add that jsDisplayPerson() ActionScript function. This starts to get into the fun stuff now: to call JavaScript
functions in Flex, you use the ExternalInterface API. You can learn more
information about it on the Flex Documentation
Site. Basically, it enables us to build wrappers to call JavaScript
functions from Flex and vice versa.
You add the ActionScript function in the <mx:Script> tags, and you also need to add an import statement for "flash.external.*".
There is not much to the function itself: first you check to see if there is an
ExternalInterface available (basically, this makes sure the Flex application is
in an HTML page). If the .swf file is embedded into an HTML page you can make the
magic happen with a call to ExternalInterface.call. You then send the information to a JavaScript function called displayPerson whose argument is the selectedItem in your DataGrid. Now
this should send an array of data of the selectedItem to JavaScript.
To learn more about what can be sent to JavaScript, check out this Adobe Documentation page. Last, you update the status label saying that the data was sent.
Otherwise, if the ExternalInterface is not available, you display an error
message in the label. Now the <mx:Script> tag looks like this:
<mx:Script> <![CDATA[ import mx.collections.ArrayCollection; import flash.external.*; public function initDG():void { var people:Array = new Array(); people.push({Name: "Charlie", Age: "23", Sex: "Male"}); people.push({Name: "Brandon", Age: "23", Sex: "Male"}); people.push({Name: "Mike", Age: "23", Sex: "Male"}); people.push({Name: "Caroline", Age: "23", Sex: "Female"}); var peopleCollection:ArrayCollection = new ArrayCollection(people); dgPeople.dataProvider = peopleCollection; dgPeople.selectedIndex = 0; } public function jsDisplayPerson():void { if (ExternalInterface.available) { ExternalInterface.call("displayPerson", dgPeople.selectedItem); lblMessage.text = "Data Sent!"; } else lblMessage.text = "Error sending data!"; } ]]> </mx:Script>
Now you get to write a bit of JavaScript code to display the
person that is being sent from Flex. So, in a set of JavaScript tags you create
the displayPerson function—remember,
the name has to match perfectly to what you told the ExternalInterface.call function in Flex to call. The
first thing you do in your JavaScript function is make sure you are not getting
a null object; and if it is null, you will display an alert. Then you can just
use the object passed as a JavaScript object and reference the appropriate
DataGrid columns using JavaScript object property syntax. All you are going to
do with them is display the values in a few table cells, but at this point you
can do anything you want with the data. So, in the HTML <script> tags, the
code looks like this:
function displayPerson(person) { if(person == null){ alert("Please select a person, or maybe I screwed up."); } else{ document.getElementById('nameDisplay').innerHTML = person.Name; document.getElementById('ageDisplay').innerHTML = person.Age; document.getElementById('sexDisplay').innerHTML = person.Sex; } }
So then, if you add a little bit of HTML like this next snippet,
you will populate a few table cells. You should be able to embed the resulting
compiled .swf file, but take notice that you need to have the allowScriptAccess property in the object and embed tags for the movie before the "JavaScript
Display" button works. You can check the source of this page if you need
more info.
<table> <tr> <td>Name:</td> <td id="nameDisplay" style="width:150px;"> </td> </tr> <tr> <td>Age:</td> <td id="ageDisplay" style="width:150px;"> </td> </tr> <tr> <td>Sex:</td> <td id="sexDisplay" style="width:150px;"> </td> </tr> </table>
Now you should be able to call any JavaScript functions from your Flex applications using the above technique.
The next thing you are going to do is set up your Flex application so that Flex functions can be called by JavaScript via ExternalInterface.
The first thing you need to do is add some code to the
application startup to initialize what Flex functions will be accessible
through external calls. You add code to the <mx:Application> tag to fire a function on the initialize event. The following code is the new
application tag. It simply calls an ActionScript function when the initialize event is fired.
<mx:Application xmlns:mx="/2006/mxml" layout="absolute" width="482" height="348" initialize="initApp()" viewSourceURL="../files/JSTutorial.mxml">
Now you can write the initApp ActionScript function. This function will check if the ExternalInterface is
available to keep from getting errors when running in the regular old Flash
player. Then it adds a callback for an ActionScript function: this function
will be referred to externally as addPerson (the first argument to addCallback)
and will map to the internal function called addPerson (the second argument to addCallback).
The initApp function should then
look like the code below, which is added in the ActionScript <mx:Script> tags.
public function initApp():void { if (ExternalInterface.available) ExternalInterface.addCallback("addPerson", addPerson); }
Now the only thing left to do in the Flex application is
create the function addPerson(), which will add people to your
DataGrid. This function takes three arguments: a string each for the name, age,
and sex of the new entry. Now, to add an item, you take the current Items in the
DataGrid and cast them as an ArrayCollection, and then add a new item using the
data you passed in. Again, this is an ActionScript function, so you need to put
it in the ActionScript <mx:Script> tags.
public function addPerson(name:String, age:String, sex:String):void { (dgPeople.dataProvider as ArrayCollection).addItem( {Name: name, Age: age, Sex: sex}); }
Now that you have the MXML and ActionScript written, you can
create some HTML and JavaScript to use the new external Flex function. The
JavaScript function you are going to make will just grab a few values from a
couple of input items on your HTML page, and then it will call the Flex
function using those values as arguments. In order to call the Flex function, you'll
use another function called getFlexApp('FlexJSTutorial').
I will go over this in just a second. So what is added to the JavaScript tag is
the following code:
function addPerson() { var name = document.getElementById('txtName').value; var age = document.getElementById('txtAge').value; var sex = document.getElementById('selSex').value; getFlexApp('FlexJSTutorial').addPerson(name, age, sex); }
So now you are wondering about this getFlexApp function—well, this is the function that actually returns the Flex app that is on the page.
I originally had an issue getting the embedded object, but
found the suggested solution on Adobe's
site. This function takes into account various types of browsers. The one
thing you need to do is make sure your object and embed tags for your .swf file have id and name attributes. These
are required for getting the Flex application. So the following function goes
in the JavaScript tag:
// This function returns the appropriate reference, // depending on the browser. function getFlexApp(appName) { if (navigator.appName.indexOf ("Microsoft") !=-1) { return window[appName]; } else { return document[appName]; }
The last thing you are going to do is create the HTML inputs
that are used in the JavaScript addPerson function. This includes two input text boxes and one input select with two
options, one for "Male" and one for "Female". There's
nothing special about these. Also, there is a button that is used to call the
JavaScript function when the onclick event occurs. These are all put in a
table for a little bit of organization:
<table style="border-spacing:5px;"> <tr> <td style="border-style:none;padding:0px;">Name:</td> <td style="border-style:none;padding:0px;"> <input id="txtName" type="text" /> </td> </tr> <tr><td style="border-style:none;padding:0px;">Age:</td> <td style="border-style:none;padding:0px;"> <input id="txtAge" type="text" /> </td> </tr> <tr><td style="border-style:none;padding:0px;">Sex:</td> <td style="border-style:none;padding:0px;"> <select id="selSex" style="width:100px;"> <option value="Male">Male</option> <option value="Female">Female</option> </select> </td> </tr> <tr> <td colspan="2" style="border-style:none;padding:0px;"> <input type="button" id="butAddPerson" onclick="addPerson()" value="Add Person" /> </td> </tr> </table>
And that about wraps it up.
After learning how to use JavaScript and Flex together, you may still be looking for more information on how to use Flex and what can be done with it. Here on the Adobe site you can find tons of tutorials and articles on building applications using Flex. I also recommend checking out Flex.org and looking over what they have available for resources; they also have some great examples on their site. Another great site for Flex tutorials is http://blog.paranoidferret.com. If you are looking to build more advanced Flex and JavaScript applications I would advise taking a look at the Flex Ajax Bridge (FABridge); note that FABridge has to be used with Flex 3 or higher. Finally, don't forget about Adobe's new application environment, Adobe AIR, which is a great platform on which to build applications.

This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 Unported License.
Charlie Key is a Flex enthusiast that is working to get his fledgling programming company, Paranoid Ferret Productions (PFP), off the ground. He and two other gentlemen work on the company in their spare time along with working on writing tutorials for the blog.