You would like to embed some javascript in your Flex application and export/invoke it to the HTML page in which your application is deployed.
To export, invoke a specially formatted javascript function using ExternalInterface.call. This function must be written as follows: "function () { myMethod = /* Your Function Here */ }". Once you've done this, your method is available via ExternalInterface.call().
There exist a class of Flex applications where the developer does not have control over the HTML wrapper in which the application is displayed, yet is asked to provide some functionality which requires the use of JavaScript. In this case, it becomes necessary to include the JavaScript methods within the compiled Flex SWF itself, and write those methods to the HTML Page upon initialization. A sample use case is that of the e-Learning developer who does not have control over the HTML page in which his course is displayed, yet is still required to provide a SCORM compliant interface with the Learning Management System's Javascript API.
It is possible to do this because ExternalInterface.call() allows us to invoke anything which resolves to a javascript method. For example, alert() is a valid JavaScript method, however so is function () { alert ('foo') }. By taking advantage of this and the loose scoping of Javascript, we can execute arbitrary JavaScript on our HTML page.
To accomplish this, you will need to take five steps.
While this is not a necessarily a time consuming step, it is nevertheless critical that "allowScriptAccess" in your SWF Embed and Object tags is set to "sameDomain" or "always". If this is not the case, then you will not be able to interface with the Javascript environment using ExternalInterface.
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
width="100" height="100"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="yourApplication.swf" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="yourApplication.swf" quality="high" bgcolor="${bgcolor}"
width="100" height="100"
allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
Any javascript method you wish to write to the HTML page will need to be wrapped in a 'setter' function that assigns a variable to the method you want to create. As you can see, the sendAlert method is not invoked lieka normal function, but is instead created as an unnamed function and assigned to a variable. This is because ExternalInterface.call() will only invoke functions.
function ()
{
sendAlert = function ( message )
{
alert ( "Message Received : " + message );
}
}
I have written a more detailed tutorial titled Embed External Text or Javascript in an Actionscript Class which goes into detail on how to cleanly and easily embed an external javascript file in an ActionScript Class. There are other ways to accomplish this as well, including the <mx:String> tag as well as via inline XML.
The below method requires that you use the Embed Metadata tag to embed your external JavaScript file as a binary class, instantiate an instance as a generic object, and then invoke toString() on the instance.
[Embed("assets/javascript/sendAlert.js", mimeType="application/octet-stream")]
private static const sendAlertJavascriptEmbed : Class;
private function get javascript ( ) : String
{
var script : Object = new sendAlertJavascriptEmbed();
return script.toString();
}
Once we have our formatted javascript file available as a string, we simply have to invoke ExternalInterface.call() on the embedded method. Note that I've added an additional check to confirm that ExternalInterface.call() is, in fact, available for use.
private function createExternalJavascriptMethods() : Boolean
{
// Check to see whether we are allowed to use the ExternalInterface
if ( ExternalInterface.available )
{
// Invoke and thus create the external method.
ExternalInterface.call( this.javascript );
return true;
}
else
{
return false;
}
}
At this point, we have successfully embedded our JavaScript file and written it to the HTML Page in which our application is deployed. The only step left is to create a proxy method which invokes our JavaScript.
public function sendAlert ( message : String ) : void
{
ExternalInterface.call( 'sendAlert', message );
}
I have attached a sample application which demonstrates how this might look encapsulated into a proxy-like class. I have also attached a sample Flex application in Examples.zip which makes use of this class.
package com.practicalflash.examples
{
import flash.external.ExternalInterface;
public class JavascriptEmbedder
{
/**
* The embedded javascript method.
*/
[Embed("assets/javascript/sendAlert.js", mimeType="application/octet-stream")]
private static const sendAlertJavascriptEmbed : Class;
/**
* Private method getter which converts the embedded javascript file to a usable string.
*/
private static function get javascript ( ) : String
{
var script : Object = new JavascriptEmbedder.sendAlertJavascriptEmbed();
return script.toString();
}
/**
* Constructor
*/
public function JavascriptEmbedder()
{
createExternalJavascriptMethods();
}
/**
* Writes the javascript method to the HTML Page.
*/
private function createExternalJavascriptMethods() : Boolean
{
// Check to see whether we are allowed to use the ExternalInterface
if ( ExternalInterface.available )
{
// Invoke and thus create the external method.
ExternalInterface.call( JavascriptEmbedder.javascript );
return true;
}
else
{
return false;
}
}
/**
* Calls our Javascript Method.
*/
public function sendAlert ( message : String ) : void
{
// Check to see whether we are allowed to use the ExternalInterface
if ( ExternalInterface.available )
{
ExternalInterface.call( 'sendAlert', message );
}
}
}
}