We use the ExternalInterface of the Flash Player to let JavaScript resize the HTML-Container of the Flex application. Our App loads dynamic content via XML and builds a list of entries. But we would like the user to use the standard browser scrollbar and not a scrollbar within the flex application. So we have to resize the HTM-Container of the Flex application, depending on its actual loaded content. Each time a new entry is added to the list, we call an JavaScript method from the Flex app via ExternalInterface to resize the HTML. This is done by using the resize-Event of Flex.

But sometimes the resize event is called up to 100 times within a second. In this cases some browsers ( sorry, but the IE seems to be ok ) didn’t get all JavaScript calls we made via ExternalInterface and some of our calls weren’t handled ( the container was not resized and our Flex list was cutted off ).

In our first version of the app we made an default call, which calls the last JavaScript-resize after a specific period again. Easy but not very elegant.

What if done now is to implement an JavaScript-Call-Stack. You put in your ExternalInterface calls and the stack will process each after an other after a given pause between the calls. If you often have the same call, maybe only with updated parameters, just like our resize-Event which has different height and width values, the stack is able to clean older calls ( which aren’t processed up to than ) and only calles the latest (in our example the JavaScript method runs ~3 times and not 100 times). The disadvantage of ExternalInterface calls via such a stack is that this is no an asynchronous process and you have to define a callback-handler if you expect an return value of the JavaScript method.

How it’s done:
Create an instance of the JsCallStack class. You should set the timer for the JavaScript calls in ms (will be 500ms by default). Maybe this value could differ from browser to browser (and maybe client hardware), i didn’t test best values for that.

// init JS function call stack
this._jsCalls = new JsCallStack();
this._jsCalls.timerInterval = 30;

It is also possible to give the stack a different mode. By default the stack will be handled as FIFO-Stack (First-In-First-Out). This means that every new call will set at the last position of the queue. It’s also possible to use it as LIFO-Stack (Last-In-First-Out), means that the last call will be handled next.

// init JS function call stack as LIFO-Stack
this._jsCalls = new JsCallStack( JsCallStack.STACK_MODE_LIFO );

Second easy step: Make your JavaScript call:

this._jsCalls.addJSCall("swfInputs.swfInputInit", {}, jsInitCompleteHandler);

This will add a JavaScript method-call to your stack. First param is the method-name (here: method „swfInputInit“ of the swfInputs-Object). The second parameter is an object which will be passed to the JavaScript method. This parameter is optional. The third parameter is the result-handler reference. If you expect any results from the JS-method, they will be handed over to this AS-method.
The return value of the addJSCall-method is an integer value of the stack position your call have ( 1 = will be processed next ). If the result is -1 the ExternalInterface isn’t available.

There are also two more parameters: The fourth is the skipOldCalls-parameter. If this is set to true (default is false) older calls of the same JS-method name will be ignored and removed from the stack. The fifth-parameter is convertToJSON. This will convert your given object, which should pass to the JS-method, to JSON.

Happy AS + JS coding.

Download (2009/12/19) JsCallStack.as (Vector)
Download (2009/03/29) JsCallStack.as (ArrayCollection)

cheers,
Sebastian

Doing nice code-comments allows you faster blog-posts:

/**
 * constructor method
 * @param stackMode:int - stack mode of handling stack entries
 */
public function JsCallStack( stackMode:int=JsCallStack.STACK_MODE_FIFO )
 
/**
 * adds an javascript function call to call stack
 * @param funcName:String - function name of js function to call
 * @param paramter:Object - object of paramters to path to the javascript function
 * 							Object will be converted to JSON and hand over an JSON-Object
 * @param resultHandler:Function - method to handler javascript results
 * @param skipOldCalls:Boolean - if true older calls in stack of the same functionname won't be
 * 								 called any more, only latest call
 * @param convert2JSON:Boolean - if true the parameter object will be converted to JSON for the javascript call
 * @return Int value of stack position, returns -1 if External Interface is not available
 */
public function addJSCall( funcName:String, parameter:Object=null, resultHandler:Function=null, skipOldCalls:Boolean=false, convert2JSON:Boolean=false ):int
 
/**
 * removes an javascript call from stack
 * @param id:int - identifier position of call which was returned from addJSCall Method
 * @return Boolean - function found an removed, false if already called
 */
public function removeJSCall( id:int ):Boolean
 
/**
 * returns if the timer is running
 * @return Boolean - is the execution timer running
 */
public function isExecutionRunning():Boolean
 
/**
 * returns the n number of registered functions at this momment
 * @return INT - numer of registered functions, which are not executed yet
 */
public function getRegisteredFunctionsCount():int
 
/**
 * setter method for timer interval value
 * @param value:Int - timer interval in milliseconds
 */
public function set timerInterval( value:int ):void
 
/**
 * getter method for timer interval
 * @return Int - set timer interval
 */
public function get timeInterval():int
 
/**
 * pauses the execution of javascript calls
 */
public function pauseExecution():void
 
/**
 * restarts the execution of javascript calls
 */
public function startExecution():void

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert