passing arrays between windows

A

Andy Fish

Hi,

I have a HTML page with javascript in it which pops up another HTML page. I
can pass simple variables fairly freely between the two pages. I can pass
objects between them two, and I have noticed that when a method is invoked
on an object, it invokes in the context of the window that created that
object.

Now, when I pass an array from one window to another, the expression:

myArray.constructor == Array

returns false in the second window.

I think I know what's happening - when I reference "Array" in the second
window, I'm talking about the second window's array constructor which is not
the constructor that was used to construct the array.

Unfortunately, this doesn't help me much. What I need is a reliable way of
telling if something is an array or not, because my test "constructor ==
Array" isn't working. Any ideas?

Andy
 
L

Lasse Reichstein Nielsen

Andy Fish said:
I have a HTML page with javascript in it which pops up another HTML page. I
can pass simple variables fairly freely between the two pages. I can pass
objects between them two, and I have noticed that when a method is invoked
on an object, it invokes in the context of the window that created that
object.

Yes. All javascript functions are closures, and their free variables refer
to the ones where they were created.
If you write
function blah(){
... window.document...
}
then the "window" variable refers to the one visible where the function
is declared, even if the function is later called by another window.
Now, when I pass an array from one window to another, the expression:

myArray.constructor == Array

returns false in the second window.

I think I know what's happening - when I reference "Array" in the second
window, I'm talking about the second window's array constructor which is not
the constructor that was used to construct the array.

That sounds correct. Functions are objects, and objects have
identities. Functions from two different pages are not the same function.
Unfortunately, this doesn't help me much. What I need is a reliable way of
telling if something is an array or not, because my test "constructor ==
Array" isn't working. Any ideas?

Don't make non-array objects with Array.prototype (or any array) as a
prototype. You never need that, since they won't act as arrays anyway.
If you need any of the Array.prototype methods for your own objects,
assign them manually.

Then, add a clone method to Object.prototype and to Array.prototype,
and whenever cloning an object, call its clone method. The one for
arrays will then make sure that the clone is also an array.

/L
 
G

Greg

Andy Fish said:
Hi,

I have a HTML page with javascript in it which pops up another HTML page. I
can pass simple variables fairly freely between the two pages. I can pass
objects between them two, and I have noticed that when a method is invoked
on an object, it invokes in the context of the window that created that
object.

Now, when I pass an array from one window to another, the expression:

myArray.constructor == Array

returns false in the second window.

I think I know what's happening - when I reference "Array" in the second
window, I'm talking about the second window's array constructor which is not
the constructor that was used to construct the array.


Couldn't you test the return value of array_name.constructor.toString() ?

Just a thought.

FWIW.
 
A

Andy Fish

Lasse Reichstein Nielsen said:
Then, add a clone method to Object.prototype and to Array.prototype,
and whenever cloning an object, call its clone method. The one for
arrays will then make sure that the clone is also an array.

aha - but this is exactly the crux of my problem.

Say window A creates an object containing an array and wants to pass it to
window B. here is a fragment of code from window A:

var userInfo = { id:"1932" name:"John Smith" groups: [ "allstaff",
"accounts" ] } ;
window.opener.updateUserInfo(userInfo);
window.close();

Calling the clone method of the userInfo object will create a new object
owned by window A, whoever calls it. In IE, both the original object and the
clone stop working completely as soon as window A is closed, which is no
good for me.

So it has to be code owned by window B that creates the clone. the problem
is that window B cannot tell whether the groups property is an array or
non-array, so it cannot create a proper clone.

From the discussions we had about 'arrayness' in a different thread, I think
maybe the best approach is to serialize the object into a single string
(using JSON) and then pass this between the windows.

Andy
 
L

Lasse Reichstein Nielsen

Andy Fish said:
aha - but this is exactly the crux of my problem.

Say window A creates an object containing an array and wants to pass it to
window B. here is a fragment of code from window A:

var userInfo = { id:"1932" name:"John Smith" groups: [ "allstaff",
"accounts" ] } ;
window.opener.updateUserInfo(userInfo);
window.close();

Calling the clone method of the userInfo object will create a new object
owned by window A, whoever calls it. In IE, both the original object and the
clone stop working completely as soon as window A is closed, which is no
good for me.

That is bad. It shouldn't stop working just because the window it was
defined in, disappears (but ofcourse, not garbage collecting the window
when it closes will risk keeping it around forever). Alas, if it does,
then we have to work around that.
So it has to be code owned by window B that creates the clone.

Not necessarily. The code might sit in window A, and even be executed
by window A, as long as it uses window B's Array and Object
constructors, right?
the problem is that window B cannot tell whether the groups property
is an array or non-array, so it cannot create a proper clone.

That is why the object/array must have its own clone method. Since code
running from page A (the call to window.opener.updateUserInfo is executed
in the context of window A's global object) and needs to use Window B's
Array and Object constructors, we have to let Window B supply these to
the clone method.

---
function cloneValue(val,toWin) {
if (typeof val == "object" && val !== null) {
return val.clone(toWin)
}
return val; // should we throw error if it is a function?
}

Object.prototype.clone = function (toWin) {
var newObj = new toWin.Object();
for (var i in this) {
newObj = cloneValue(this,toWin);
}
return newObj;
}

Array.prototype.clone = function (toWin) {
var newArr = new toWin.Array();
for (var i in this) {
newArr = cloneValue(this,toWin);
}
return newArr;
}
---
You can also add clone methods to Date and Regexp prototypes, or even to
Number and String. You will need these clone methods on page B, where
the value to be cloned is created.

You then call this from the updateUserInfo function as:

function updateUserInfo(userInfo) {
...
cloneValue(userInfo,window)
...
}

Due to scope rules, that "window" variable refers to window B's global
object.

Warning: code only tested in IE6.
From the discussions we had about 'arrayness' in a different thread, I think
maybe the best approach is to serialize the object into a single string
(using JSON) and then pass this between the windows.

Never give up! Never surrender!

/L
 
A

Andy Fish

you are truly too clever for your own good ;-))

I hope this code can make it onto a FAQ somewhere

Lasse Reichstein Nielsen said:
Andy Fish said:
aha - but this is exactly the crux of my problem.

Say window A creates an object containing an array and wants to pass it to
window B. here is a fragment of code from window A:

var userInfo = { id:"1932" name:"John Smith" groups: [ "allstaff",
"accounts" ] } ;
window.opener.updateUserInfo(userInfo);
window.close();

Calling the clone method of the userInfo object will create a new object
owned by window A, whoever calls it. In IE, both the original object and the
clone stop working completely as soon as window A is closed, which is no
good for me.

That is bad. It shouldn't stop working just because the window it was
defined in, disappears (but ofcourse, not garbage collecting the window
when it closes will risk keeping it around forever). Alas, if it does,
then we have to work around that.
So it has to be code owned by window B that creates the clone.

Not necessarily. The code might sit in window A, and even be executed
by window A, as long as it uses window B's Array and Object
constructors, right?
the problem is that window B cannot tell whether the groups property
is an array or non-array, so it cannot create a proper clone.

That is why the object/array must have its own clone method. Since code
running from page A (the call to window.opener.updateUserInfo is executed
in the context of window A's global object) and needs to use Window B's
Array and Object constructors, we have to let Window B supply these to
the clone method.

---
function cloneValue(val,toWin) {
if (typeof val == "object" && val !== null) {
return val.clone(toWin)
}
return val; // should we throw error if it is a function?
}

Object.prototype.clone = function (toWin) {
var newObj = new toWin.Object();
for (var i in this) {
newObj = cloneValue(this,toWin);
}
return newObj;
}

Array.prototype.clone = function (toWin) {
var newArr = new toWin.Array();
for (var i in this) {
newArr = cloneValue(this,toWin);
}
return newArr;
}
---
You can also add clone methods to Date and Regexp prototypes, or even to
Number and String. You will need these clone methods on page B, where
the value to be cloned is created.

You then call this from the updateUserInfo function as:

function updateUserInfo(userInfo) {
...
cloneValue(userInfo,window)
...
}

Due to scope rules, that "window" variable refers to window B's global
object.

Warning: code only tested in IE6.
From the discussions we had about 'arrayness' in a different thread, I think
maybe the best approach is to serialize the object into a single string
(using JSON) and then pass this between the windows.

Never give up! Never surrender!

/L
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,207
Latest member
HelenaCani

Latest Threads

Top