Is a Flex object any different from a JS object?

General Discussion of Scripting for Flex, Flash & CS SDK

Moderators: Tom, Kukurykus

undavide

Is a Flex object any different from a JS object?

Post by undavide »

Hello,
I'm trying to pass an object from Actionscript to Javascript and I'm getting mad!
I follow the well known HostObject trick described by Zak Nelson (see here) to embed a JSX file: basically I've a very simple:

Code: Select all[ Embed (source= "myScript.jsx" , mimeType= "application/octet-stream" )]
private static var myScriptClass:Class;
private static var jsxInterface:HostObject;

public function appComplete():void{
   // embed the JSX
   jsxInterface = HostObject.getRoot(HostObject.extensions[0]);
   jsxInterface.eval( new myScriptClass().toString());
}

// click handler for a button - calls the JS
protected function button1_clickHandler(event:MouseEvent):void {
   var param:Object = new Object();
   param.radius = 10;
   jsxInterface.main(param);
}
As you see, I pass the "param" object to JS.
In the Javascript, the main() function is trivial:

Code: Select allvar main = function (obj) {
   var d = objectToDescriptor (obj, "myString");
}

// The following comes from Adobe
///////////////////////////////////////////////////////////////////////////////
// Function: objectToDescriptor
// Usage: create an ActionDescriptor from a JavaScript Object
// Input: JavaScript Object (o)
//        object unique string (s)
//        Pre process converter (f)
// Return: ActionDescriptor
// NOTE: Only boolean, string, number and UnitValue are supported, use a pre processor
//       to convert (f) other types to one of these forms.
// REUSE: This routine is used in other scripts. Please update those if you
//        modify. I am not using include or eval statements as I want these
//        scripts self contained.
///////////////////////////////////////////////////////////////////////////////
function objectToDescriptor (o, s, f) {
   if (undefined != f) {
      o = f(o);
   }

   var d = new ActionDescriptor;
   var l = o.reflect.properties.length;
   d.putString( app.charIDToTypeID( 'Msge' ), s );
   for (var i = 0; i < l; i++ ) {
      var k = o.reflect.properties.toString();
      if (k == "__proto__" || k == "__count__" || k == "__class__" || k == "reflect")
         continue;
      var v = o[ k ];
      k = app.stringIDToTypeID(k);
      switch ( typeof(v) ) {
         case "boolean":
            d.putBoolean(k, v);
            break;
         case "string":
            d.putString(k, v);
            break;
         case "number":
            d.putDouble(k, v);
            break;
         default:
         {
            if ( v instanceof UnitValue ) {
               var uc = new Object;
               uc["px"] = charIDToTypeID("#Pxl"); // pixelsUnit
               uc["%"] = charIDToTypeID("#Prc"); // unitPercent
               d.putUnitDouble(k, uc[v.type], v.value);
            } else {
               throw( new Error("Unsupported type in objectToDescriptor " + typeof(v) ) );
            }
         }
      }
   }
    return d;
}
Well, I can't make it work, it fires: "Error: undefined is not an object".
The fun part is that if, in JS, I check the obj.radius property, it's there! And the value is correct. Yet, the Object isn't suitable to be put inside a descriptor. Why on earth I can't say.

Zak reports that:
This technique can also be used to pass complex objects between the two different contexts. The magic is in the property hostObjectDelegate, which is found on each Creative Suite ActionScript Wrapper. Consider sending a document object to JavaScript from ActionScript:
jsxInterface.sendDocumentToJSX(app.documents.item(0).hostObjectDelegate );
So I've tried with:

Code: Select allprotected function button1_clickHandler(event:MouseEvent):void {
   var param:Object = new Object();
   param.radius = 10;
   jsxInterface.main(param.hostObjectDelegate); // undefined
}
Or also:

Code: Select allprotected function button1_clickHandler(event:MouseEvent):void {
   var param:HostObject = new HostObject();
   param.radius = 10;
   jsxInterface.main(param.hostObjectDelegate); // undefined
}
And eventually

Code: Select allprotected function button1_clickHandler(event:MouseEvent):void {
   var param:HostObject = new HostObject();
   param.radius = 10;
   jsxInterface.main(param); // Error: Host object flash.external.HostObject is invalid
}
But without any luck.
The object is passed to JS (in the very first version I've written up above in the post), I can read its properties, but as long as the objectToDescriptor() function is involved - errors are fired.
Mind you, a dummy object created within JS works flawlessly, so am I wondering: is a Flex object any different form a JS one?!

Code: Select allvar dummy = {
   radius: 10;
}
Any help is really appreciated!
Thanks,

Davide
undavide

Is a Flex object any different from a JS object?

Post by undavide »

I still can't say how is the Flex object different from the JS one, but I've restricted the error in this objectToDescriptor() line:

Code: Select all   var l = o.reflect.properties.length;
Apparently, an object coming from Flex can't be reflected.

A viable workaround is to duplicate the object within the JS before sending it, so that:

Code: Select allvar duplicateObj = function (obj) {
    var newObj = new Object();
    for (var prop in obj) {
        newObj[prop] = obj[prop];
        }
    return newObj;
}

var main = function (obj) {
   var d = objectToDescriptor (duplicateObj(obj), "myString");
}

It looks very weird to my eyes but at least it doesn't break anymore. I'm pretty curious though, if someone had an explanation.