Julian Jelfs’ Blog

Solution to the cross-frame instanceof scope problem

Posted in Javascript by julianjelfs on January 15, 2010

In my previous post I explained how I ran into the problem that dateB defined on frameB would return false if you execute dateB instanceof Date in frameA. I thought that this was because the data somehow got mangled when marshalled from one window to another. In fact it is nothing to do with that. The instanceof function is working entirely correctly, it’s just maybe not doing what you expect.

When you write (dateB instanceof Date) you are really asking was dateB created with function Date. Now when you add the implicit scope you begin to see why it doesn’t work the way you want. dateB was created in frameB with the function frameB.Date. So when you say dateB instanceOf frameA.Date as you implicitly are when you run this code in frameA, then of course it should and does return false.

If you explicitly call dateB instanceof frameB.Date it still returns true.

If you bear this in mind when calling functions that return data on other frames you can get round it. One approach which I have taken is shown here:

var frameB = top.frames["frameB"];

var dateB = crossFrame(frameB, frameB.getMeADate);

alert(dateB instanceof Date);     //give true

function crossFrame(target, func, parms){
    var result = func.apply(target, parms);
    result = tagDates.call(target, result);
    tagDates.call(target, parms);
    fixDates(parms);
    return fixDates(result);
}
function fixDates(val){
    if (val == null) return val;
    if (val["_date"]!==undefined) {        
        return new Date(val);
    }
    if (typeof (val) != 'object') return val;
    if (val instanceof Array) {
        for (var j = 0,len=val.length; j < len; j++) {
            val[j] = fixDates(val[j]);
        };
        return val;
    }
    for (var prop in val)
        val[prop] = fixDates(val[prop]);
    return val;
}

function tagDates(val){
    if (val instanceof Date) {
        val._date = true;
        return val;
    }
    if (typeof (val) != 'object') return val;
    if (val == null) return val;
    if (val instanceof Array) {
        for (var j = 0,len=val.length; j < len; j++) {
            val[j] = tagDates(val[j]);
        };
        return val;
    }
    for (var prop in val)
        val[prop] = tagDates(val[prop]);
    return val;
}

So we pass the target frame and the target function and the arguments array to the function crossFrame. Inside crossFrame we call the function on the target frame and get the results. At this point we are in calling frame scope. We then call tagDates using the target frame as scope. In this scope we can correctly identify the dates in the data. For each one we find, add an attribute so that we can identify it as a date later.

Then back in the calling scope we call fixDates which looks for the objects we tagged as dates and overwrites them with an equivalent Date created in the calling scope.

This means that when the data is returned from the call to crossFrame, any dates will have been re-created in the calling scope and any call to instanceof will work as expected.

The code above is not complete because it only handles dates. That’s all I have a problem with so it works for me but it could easily be extended for any other type because the underlying problem is not about types it is about scope.

Advertisements

One Response

Subscribe to comments with RSS.

  1. […] Posted in Javascript by julianjelfs on January 24, 2010 So in my previous posts here and here I described a problem I was having with Microsoft Ajax script library serialisation of Dates that […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: