« Widgets and Social Commerce: news from the front of Web 2.0 | Main | Choosing the appropriate RIA technology »

Bug when modifying DOM hierarchy with Javascript using ExternalInterface

I was working on a project using Javascript and Flex. The communication between ActionScript and Javascript is managed by the ExternalInterface class, it is great, simple and it works without problems. But if you are using a DOM function, as appendChild, on a DOM node that contains a Flex object, you can see a strange behavior: Internet Explorer will return an unspecified error and Firefox will refresh your Flex movie. Mozilla had probably the same error of IE, but they reported and corrected it using the refresh workaround. It can be sometimes a good solution, but not always because you could lose all the data in the flex movie. In some special conditions this ExternalInterface bug can make your browser crash.
Let's see when this bug appears:
we need an HTML page with a flex movie inside a div with id "swfMovie", two Javascript functions and a form with two buttons.

Javascript:

function thisMovie(movieName) {
  var isIE = navigator.appName.indexOf("Microsoft") != -1;
  return (isIE) ? window[movieName] : document[movieName];
}
function appendSwf() {
  document.getElementById("container").appendChild(document.getElementById("swfMovie"));
}

The first is the standard JS function used to find a swf movie in an HTML page. The second method use the appendChild function to change the DOM hierarchy and move the div containing the swf movie.

HTML Form:

<form>
  <input type="button" onclick="thisMovie('ExtInt_bug').ASFunction();" value="Call AS function" />
  <input type="button" onclick="appendSwf();" value="Append" />
</form>

The "Call AS function" button calls the Actionscript method exposed by the ExternalInterface class in the swf movie. It simply show an alert message confirming the correct execution of the function.
The "Append" button calls the JS function appendSwf that moves down the div containing the flex movie.

Actionscript:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="onCreationComplete()" width="300" height="300">
  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;
      import flash.external.*;
      
      private function onCreationComplete():void {
          ExternalInterface.addCallback("ASFunction", ASFunction);
      }
      
      public function ASFunction():void {
        Alert.show("ExternalInterface works");
      }
    ]]>
  </mx:Script>
</mx:Application>

Let's see the bug in action:
go to the test page, click the "Call AS function" button, then click the "Append" button. If you are using Firefox you see that the Alert message disappears, this is caused by the refresh of swf movie. Using Internet Explorer you can notice that the "Append" button works correctly, but it fails when you click again "Call AS function".
There is not a real solution to this bug, but there's a workaround to avoid the JS error in IE and make IE works as Firefox. Just add a line in the appendSwf function:

function appendSwf() {
  document.getElementById("container").appendChild(document.getElementById("swfMovie"));
  document.getElementById("swfMovie").innerHTML = document.getElementById("swfMovie").innerHTML;
}

The second statement simply refresh the flex movie such as in Firefox, registering again the External Interface callback.
Both browsers will crash if you change the Actionscript ASFunction in:

public function ASFunction():void {
  ExternalInterface.call("appendSwf");
}

I have tested this bug only on Internet Explorer and Firefox on Windows and I think there's not a solution yet. I hope someone will have some good news on it.

TrackBack

TrackBack URL for this entry:
http://blog.comtaste.com/mt-tb.cgi/35

Comments (2)

Ryan:

I also ran in to this problem. Except mine came with using FusionCharts, and the Chart would refresh whenever an onclick event was initially triggered.

fatman:

There is an workaround for this, and it involves using a proxy swf file.

The proxy and the target swf will both use LocalConnection for communication, but you must not touch the proxy swf with the DOM, so it will be able to provide ExternalInterface access.

Have fun!

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

About

This page contains a single entry from the blog posted on November 20, 2007 2:48 PM.

The previous post in this blog was Widgets and Social Commerce: news from the front of Web 2.0.

The next post in this blog is Choosing the appropriate RIA technology.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33