Flex applications require the Flash Player runtime environment to work. For this reason, it is common to think of Flex applications as being confined to Flash Player. However, it is entirely possible for a Flex application to communicate with the host application. For example, if a Flex application is running within a web browser, the application can interact with the browser. If a Flex application is running within a desktop executable, it can interact with that executable. This lets you create integrated applications that span beyond the Flash Player context.
Flex application/host application communication takes place via a
Flash Player class called flash.external.ExternalInterface
. ExternalInterface
allows you to make synchronous calls to host application
methods from the Flex application, and from the host application to Flex
application methods. ExternalInterface
is quite simple to work with, and in most cases it is quite
appropriate.
The flash.external.ExternalInterface
class defines
two static methods, named call()
and
addCallback()
, enabling
Flex-to-host-application communication and host-application-to-Flex
communication, respectively.
The call()
method allows you to
call a method of the host application by passing it the name of the
method. If the host application method expects parameters, you can pass
those parameters to the call()
method
following the name of the host application method. For example, the
following will call the alert()
JavaScript method when the Flex application is run in a web
browser:
ExternalInterface.call("alert", "Test message from Flex");
The call()
method works
synchronously. For example, the JavaScript confirm()
function creates a new dialog with
OK and Cancel buttons. The confirm dialog pauses the application until
the user clicks on a button, at which time it returns either True
(OK) or False
(Cancel).
var option:Boolean = ExternalInterface.call("confirm", "Do you really want to close the application?");
Of course, the host application functions can be custom functions as well.
If you want to call a Flex method from the host application, you
must register the method within the Flex application using ExternalInterface.addCallback()
. The addCallback()
method lets you
register a particular function or method with an alias by which the
method or function may be called from the host application. For example,
the following registers Alert.show
as
showAlert
:
ExternalInterface.addCallback("showAlert", Alert.show);
You can then call the Alert.show
method by way of the showAlert
alias from the host
application.
Within the host application you must retrieve a reference to the
Flash Player instance that is running the .swf. You can then call the method by its
alias directly from the reference. For example, if getFlexApplicationReference()
is a function
within the host application that returns a reference to the Flash Player
instance, the following would launch an alert:
getFlexApplicationReference().showAlert("Alert message from host application");
In JavaScript, the Flash Player reference is different depending
on the type of browser (IE or non-IE). In IE you can retrieve a
reference to the Flash Player instance by window.
id
,
where id
is the value of the id
parameter of the <object>
tag, and in non-IE browsers the
reference is document.
name
,
where name
is the value of the name
attribute of the <embed>
tag. The following JavaScript
function determines the browser type and returns the correct reference
where both the id
parameter and the
name
attribute are Example
:
function getFlexApplicationReference() { if (navigator.appName.indexOf("Microsoft") != −1) { return window.Example; } else { return document.Example; } }
ExternalInterface
might seem a
little confusing until you see an example or two. In this section and
the next, we’ll look at a few simple examples that should clarify how
ExternalInterface
works. This first
application simply allows a Flex application to call to JavaScript in a
hosting web browser so that it sets the status bar message as the user moves
the mouse over Flex buttons.
Firefox disables JavaScript access to window.status
by default, and therefore this
example might not work with the default Firefox configuration.
This application uses one simple MXML document and one HTML page. The MXML document should contain the code shown in Example 16-12.
Example 16-12. ExternalInterfaceExample.mxml
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ private function rollOverHandler(event:MouseEvent):void { ExternalInterface.call("setStatus", event.currentTarget.label); } ]]> </mx:Script> <mx:VBox> <mx:Button label="A" rollOver="rollOverHandler(event)" /> <mx:Button label="B" rollOver="rollOverHandler(event)" /> <mx:Button label="C" rollOver="rollOverHandler(event)" /> <mx:Button label="D" rollOver="rollOverHandler(event)" /> </mx:VBox> </mx:Application>
This MXML document creates four buttons. Each button has a
different label. Using event handlers for the rollOver
event each button notifies the rollOverHandler()
method when the user has
moved the mouse over the button. The rollOverHandler()
method uses ExternalInterface.call()
to call the setStatus
method that is defined using
JavaScript in the HTML page within which the application is to be
embedded. The label for the corresponding button gets passed to the
setStatus
function.
The HTML page should contain the standard HTML template for
embedding Flex content. In addition, it must define the setStatus()
JavaScript function as
follows:
<script language="JavaScript" type="text/javascript"> <!-- function setStatus(value) { window.status = value; } // --> </script>
When you test this application, the browser status bar message changes as you move the mouse over the Flex buttons.
There are cases where you may want to display the majority of a form in HTML, but you want to utilize Flex components for one or more of the form elements. For example, you may want to use sliders, color pickers, or, as in this example, date choosers.
In this simple example, we’ll create a basic HTML form with a
checkbox and a small embedded Flex application. The Flex application
consists of one date chooser component. The checkbox simply enables and
disables the date chooser. Additionally, to highlight the synchronous
nature of ExternalInterface
the Flex
application makes a request to the HTML page for an array of disabled
dates, which it uses to disable those dates in the date chooser.
For this application, we’ll first create the HTML page as shown in Example 16-13. Note that this example uses SWFObject, which is a JavaScript library described in Chapter 21.
Example 16-13. ExternalInterface example HTML page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <title>Flex Example</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript"> swfobject.registerObject("flexApplication", "9.0.0"); function getDisallowedDates() { return [new Date()] } </script> </head> <body> <input name="checkbox" type="checkbox"onChange="swfobject.
getObjectById('flexApplication').setEnabled(this.checked)"
/> <div> <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="175" height="180" id="flexApplication"> <param name="movie" value="Flex3.swf" /> <!--[if !IE]>--> <object type="application/x-shockwave-flash" data="Flex3.swf" width="175" height="180"> <!--<![endif]--> <p>This site is best viewed as a Flex application, which requires Flash Player 9. For users who prefer not to use Flash Player we have provided a <a href='textVersion.html'>text-only version of the site</a/>.</p> <!--[if !IE]>--> </object> <!--<![endif]--> </object> </div> </body> </html>
In the preceding HTML code, we’ve highlighted a few of the key
things to notice. You’ll see that the checkbox uses an onChange
handler to call the setEnabled()
method of the Flex application,
passing it the checked value of the checkbox. This means that the Flex
application must map a method to the setEnabled()
name as a valid ExternalInterface
callback. You’ll
also see that the code defines a JavaScript method called getDisallowedDates()
. This is callable from the Flex application to retrieve an
array of Date
objects.
The Flex application consists of just one MXML document, as shown in Example 16-14.
Example 16-14. ExternalInterface example MXML Flex3.mxml
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)" width="175" height="180"> <mx:Script> <![CDATA[ private function initializeHandler(event:Event):void { var disallowedDates:Array = ExternalInterface.call("getDisallowedDates"); calendar.disabledRanges = disallowedDates; ExternalInterface.addCallback("setEnabled", setEnabled); } public function setEnabled(value:Boolean):void { calendar.enabled = value; } ]]> </mx:Script> <mx:DateChooser id="calendar" enabled="false" /> </mx:Application>
In this code, you’ll notice that when the application initializes,
it calls the getDisallowedDates()
JavaScript
function in a synchronous fashion, retrieving the returned value
immediately. It then uses that value—an array of Date
objects—to specify the disabled ranges
for the date chooser instance. Because ExternalInterface
automatically serializes and
deserializes arrays and Date
objects,
this code works without having to further convert the returned
values.
When the application initializes, it also registers setEnabled()
as an ExternalInterface
callback. That is
what allows the JavaScript-to-Flex communication.
The setEnabled()
method takes
the parameter and assigns it to the enabled
property of the date chooser. Again,
because Boolean values are automatically serialized and deserialized,
the code works as is.