IE 5+ bug? How to store complex objects whilst changing pages

F

F. Da Costa

Hi,

Does anybody know why IE5+ does *not* honour array objects (like a table)
across a session?

Example:
Frame A contains a var tableVar which is set via form Frame B (on init)
using top.A.tableVar = document.getElementById("someTable");

As long as Frame B is *not* 'refreshed/ reloaded' witk another page the
variable in Frame A is ok.
However, when the page is changed it just 'kills' the rows in tableVar.rows
(the lenght just turns to 0).

When tested with something simple like a String (instead of a table) the
above mechanism works as expected.

After two full days of mucking about this is strting to smell funny.
Does anybody have any idea/ suggestion as to the what and/ or why of this
behaviour.

TIA,
Fermin DCG
 
R

Richard Cornford

F. Da Costa said:
Does anybody know why IE5+ does *not* honour array objects
(like a table) across a session?

A table is not an array it is a host object (DOM Element).
Example:
Frame A contains a var tableVar which is set via form Frame B (on
init) using top.A.tableVar = document.getElementById("someTable");

For the best cross-browser support named frames are best referenced as
named properties of the global - frames - collection (of the parent
frame):-

top.frames.A.tableVar = . etc.

So you are assigning a reference to an element of a document in one
frame to a variable in another.
As long as Frame B is *not* 'refreshed/ reloaded' witk another page
the variable in Frame A is ok.

As it should be.
However, when the page is changed it just 'kills' the rows in
tableVar.rows (the lenght just turns to 0).

When you change the contents of a frame you destroy the document it
contains. All of the elements of that document become available for
garbage collection. Holding a reference to one of those elements in
another frame should (may) prevent the element itself and its
descendants from being garbage collected but as its document object has
been destroyed it is probably unrealistic to expect that element to
remain functional.

It is also usual for DOM implementations not to allow an Element (or
Node) from one document to be inserted in another (except using the
document.importNode method, which actually creates a copy of the
"imported" Node for the current document and leaves the original
unchanged).
When tested with something simple like a String (instead of a table)
the above mechanism works as expected.

Strictly the previous value assigned to the variable in the other frame
also "works", in the sense that it has been assigned a reference to an
object and it is still holding that value after the page has changed. It
is just that the object referred to has been radically altered by the
fact that its document has been destroyed (in addition, its global
context/window(frame) object has also been distorted).
After two full days of mucking about this is strting to smell funny.
Does anybody have any idea/ suggestion as to the what and/ or
why of this behaviour.

Trying to store a reference to a table is a shortcut to trying to store
the information within that table, probably the best solution is to
extract the required information from the table and store that in a
JavaScript object belonging to frame A. Probably an object customised to
ease the process of restoring/inserting the information to new elements
created in the other frame.

Richard.
 
L

Lasse Reichstein Nielsen

F. Da Costa said:
Does anybody know why IE5+ does *not* honour array objects (like a
table) across a session?

Tables are not arrays.
Example:
Frame A contains a var tableVar which is set via form Frame B (on
init) using top.A.tableVar = document.getElementById("someTable");

You store a table element (not an array) belonging to the document in
Frame B. DOM elements are bound to the document that created them,
and can't be inserted into other documents. It is an "active" element
that is represented directly in the page, and reflects all changes
made ....
As long as Frame B is *not* 'refreshed/ reloaded' witk another page
the variable in Frame A is ok.
However, when the page is changed it just 'kills' the rows in
tableVar.rows (the lenght just turns to 0).

.... including removing all children when the page is unloaded.
There is no longer a table in that document, and it sure doesn't
have children, so no rows.
When tested with something simple like a String (instead of a table)
the above mechanism works as expected.

Strings are simple objects. DOM elements are not. They won't survive
the death of their page any more than the document.images collection
would.
After two full days of mucking about this is strting to smell funny.
Does anybody have any idea/ suggestion as to the what and/ or why of
this behaviour.

What you can do is to store a clone of the table element instead of
the element itself. If you use the correct document.importNode method,
it should make a clone that is linked to the document you store it in.

top.frames['A'].myTableClone =
top.frames['A'].document.importNode(getElementById("MyTableId"),true);

And when you need to use it again:

var myTableClone = document.importNode(top.frames['A'].myTableClone,true);

(but notice that document.importNode is DOM 2, so IE doesn't support it)

/L
 
F

F. Da Costa

Richard said:
A table is not an array it is a host object (DOM Element). It most certainly is

For the best cross-browser support named frames are best referenced as
named properties of the global - frames - collection (of the parent
frame):-
Point taken but judging from you comment this is not where the issue lies
top.frames.A.tableVar = . etc.

So you are assigning a reference to an element of a document in one
frame to a variable in another. Correct

When you change the contents of a frame you destroy the document it
contains. All of the elements of that document become available for
garbage collection. Holding a reference to one of those elements in
another frame should (may) prevent the element itself and its
descendants from being garbage collected but as its document object has
been destroyed it is probably unrealistic to expect that element to
remain functional.
Ahh, I take your point but wouldn't that imply that this should not work
with Gecko based browsers either? Which (unfortunately?) it does!
It is also usual for DOM implementations not to allow an Element (or
Node) from one document to be inserted in another (except using the
document.importNode method, which actually creates a copy of the
"imported" Node for the current document and leaves the original
unchanged).
Ok, updating my DOM knowledge here. Does this mean that every frame has got
its own DOM or is the DOM still 'defined at browser level' if you wish and
are the frames just nodes in the overall structure?
I was under the impression that the latter is the case.
Strictly the previous value assigned to the variable in the other frame
also "works", in the sense that it has been assigned a reference to an
object and it is still holding that value after the page has changed. It
is just that the object referred to has been radically altered by the
fact that its document has been destroyed (in addition, its global
context/window(frame) object has also been distorted).
In summary: the variable that holds the reference indeed still contains it.
Because 'further down' in the reference part of it is 'linked' to a
'disappearing' document this part becomes 'stuffed up.
I (think) I can follow the reasoning but I'm still not getting the fact
that Gecko is *not* compliant with *this* behaviour.
Actually, should it not be irrelevant how complex a structure is? Either
you loose cit or you don't. the table as a whole is part of the document so
wouldn't it be more logical for it to disappear as a whole and not just its
rows?
Trying to store a reference to a table is a shortcut to trying to store
the information within that table,
Absolutely correct, basically its a state keeping issue.
probably the best solution is to
extract the required information from the table and store that in a
JavaScript object belonging to frame A. Probably an object customised to
ease the process of restoring/inserting the information to new elements
created in the other frame.

Ok, couldn't cloneNode be used to basically 'do' this.
On init one just clones the 'skeleton'
On subsequent modification one just clones the required part and inserts it
into the static structure.

IF the above would hold can I than still 'replace' the not required table
coming in on the new page with the 'stored' static one or would that result
in funny behaviour as well.

Following the code (part of the static frame) used by the 'dynamic' frame
to modify the structure shown.

Thx for the reply.

=============================================
var _staticTable;
var _tbodyRows;

/**
* This function is responsible for inserting a new tBody in an extisting
table.
* @param win = the window from where the function is called (mainContent)
* @param table = the ID of the table where the tbody needs to be inserted
*/
function createTbody(win, tBodyID) {
var windoc = win.document;
var myDiv = windoc.getElementById("doc");

// creates/ get an element of type TABLE
if (tBodyID=="" || !_staticTable) {
_staticTable = windoc.getElementById("treeTable");
return;
}
else {
var defaultTable = windoc.getElementById("treeTable");
myDiv.replaceChild(_staticTable, defaultTable);
}

// creates an element whose tag name is TBODY
var mytablebody = windoc.getElementById(tBodyID);
// creating all cells within the rows
for(var j=0, rLen=_tbodyRows.length; j<rLen; j++) {
// creates an element whose tag name is TR
var mycurrent_row=windoc.createElement("TR");

// start working on the columns
for(var i=0, cLen=_tbodyRows[0].length; i < cLen; i++) {
// creates an element whose tag name is TD
var mycurrent_cell=windoc.createElement("TD");
// creates a Text Node
var currenttext=windoc.createTextNode(_tbodyRows[j]);
// appends the Text Node we created into the cell TD
mycurrent_cell.appendChild(currenttext);
// appends the cell TD into the row TR
mycurrent_row.appendChild(mycurrent_cell);
}
// appends the row TR into TBODY
mytablebody.appendChild(mycurrent_row);
}
}
 
F

F. Da Costa

Lasse said:
Tables are not arrays.
I'll be more carefull in the future with my naming (Richard Cornford also
chewed me on this one ;)).
You store a table element (not an array) belonging to the document in
Frame B. DOM elements are bound to the document that created them,
and can't be inserted into other documents. It is an "active" element
that is represented directly in the page, and reflects all changes
made ....
This is fine because I do not want to move it to another document 'to be
shown'.
.... including removing all children when the page is unloaded.
There is no longer a table in that document, and it sure doesn't
have children, so no rows.


Strings are simple objects. DOM elements are not. They won't survive
the death of their page any more than the document.images collection
would.
That might be the case but why then would the Gecko browsers (Moz 1.6b + FB
0.7+ ) not have a problem with this. They hold on to the structure as
stored to be reused at a later stage when required in the page the user is
looking at.
After two full days of mucking about this is strting to smell funny.
Does anybody have any idea/ suggestion as to the what and/ or why of
this behaviour.


What you can do is to store a clone of the table element instead of
the element itself. If you use the correct document.importNode method,
it should make a clone that is linked to the document you store it in.

top.frames['A'].myTableClone =
top.frames['A'].document.importNode(getElementById("MyTableId"),true);

And when you need to use it again:

var myTableClone = document.importNode(top.frames['A'].myTableClone,true);

(but notice that document.importNode is DOM 2, so IE doesn't support it)
Ahh, but you probably guessed as well. *This* is where the problem lies. I
need a way to dynamically build a potentially biggish table without
bothering the server too much.

Would the cloneNode be a possibility instead?

Thx 4 your effort (again).

Fermin DCG
 
L

Lasse Reichstein Nielsen

F. Da Costa said:
Ahh, I take your point but wouldn't that imply that this should not
work with Gecko based browsers either? Which (unfortunately?) it does!

There is nothing in the DOM specification that says what should happen
when a browser unloads a page. The DOM specification only talks about
what you can do with nodes, and nothing about browsers. When the
browser loads the document, it creates a DOM compliant object
structure, and when it unloads the document, it ... well, it does
whatever it wants to do. It seems IE destroys the document structure
by removing all children from the parent (probably in order to better
garbage collect the memory). And apparently Mozilla doesn't change the
document structure, it just forgets it. Neither is wrong.
Ok, updating my DOM knowledge here. Does this mean that every frame
has got its own DOM or is the DOM still 'defined at browser level' if
you wish and are the frames just nodes in the overall structure?
I was under the impression that the latter is the case.

The DOM is a specification of how some objects should behave. The
nodes that are created by the browser in accordance with this
specification are just host objects with references to each other.

There is one DOM, it's published by W3C. What I think you are thinking
of is the document's DOM node tree, which is a tree-like structure of
DOM (compliant) Node objects.

These nodes can refer to each other between windows, but each
document's node tree can only contain nodes created by that document
(either when loaded, or using that document's createElement or
createTextNode methods).

Actually, should it not be irrelevant how complex a structure is?
Either you loose cit or you don't. the table as a whole is part of the
document so wouldn't it be more logical for it to disappear as a whole
and not just its rows?

The rows didn't disappear. The link between the table element node and
its child nodes have been severed, just as I'll bet the table node's
parentNode reference is also null. But the table element's node object
must still exist, *because you have a reference to it*. In Javascript,
and indeed most garbage collected object oriented langauges, a reference
to an object will always point to that object. The object can't be
destroyed, because then your reference would point to ... what?
Ok, couldn't cloneNode be used to basically 'do' this.

It will make a clone that is still attached to the same document.
That is why I suggested importNode, because the clone it makes
is linked to a different document.

/L
 
R

Richard Cornford

Ahh, I take your point but wouldn't that imply that this should not
work with Gecko based browsers either? Which (unfortunately?) it does!

No, it implies that you should have no expectation of it working with
Gecko browsers, and if it does you should have no expectation of it
continuing to work with Gecko browsers. When it comes to host objects
(which DOM elements are) the ECMA Script specifications don't get
involved so what happens is largely up to the implementers (at least in
the areas not covered by the W3C DOM specifications/recommendations (and
even then only the Core DOM is mandatory)).

If it works with Gecko browsers now then you got lucky. That happens: I
remember a post from someone who wanted to create a cross-frame pop-up
menu and had discovered that creating/appending an absolutely positioned
DIV element in/to the topmost frameset document in one Mozilla release
allowed that DIV to float across frame boundaries, displaying over all
of them. The resulting DOM was invalid as DIVs cannot be children of
FRAMESETs and the attempt should have thrown a HIERARCHY_REQUEST_ERR
exception. The previous versions of Mozilla had not allowed it, and the
subsequent versions did not allow it, so I don't imagine the menu script
he had written using it lasted very long.
Ok, updating my DOM knowledge here. Does this mean that every frame
has got its own DOM or is the DOM still 'defined at browser level'
if you wish and are the frames just nodes in the overall structure?
I was under the impression that the latter is the case.

There are a number of different things that are referred to as DOM
(often incorrectly ), what I am referring to above as "DOM
implementations" are implementations of the W3C Core DOM specification
(which, in web browsers, usually include the W3C HTML DOM and other W3C
standards like events). The W3C DOM specifications *only* cover a -
Document - object and its descendants/content, they say noting about
window/frame/global objects. Web Browsers have an Object Model that
(with a frameset) does represent a hierarchical structure of
window/frame/global objects and those objects each contain a document
object that (more or less, mostly more with modern browsers) implements
the W3C DOM.

In summary: the variable that holds the reference indeed still contains
it. Because 'further down' in the reference part of it is 'linked' to a
'disappearing' document this part becomes 'stuffed up.
I (think) I can follow the reasoning but I'm still not getting the fact
that Gecko is *not* compliant with *this* behaviour.
Actually, should it not be irrelevant how complex a structure is? Either
you loose cit or you don't. the table as a whole is part of the document
so wouldn't it be more logical for it to disappear as a whole and not
just its rows?

This behaviour is outside of any specifications so you are just
experiencing differences in implementations of the browser object model,
the W3C DOM and the garbage collecting system. Nobody is right or wrong
they have just made different decisions about how to implement their
browsers (and probably included different bugs).

But if you are examining the residual structure of elements under the
table only via its - rows - collection then you haven't verified that
the rows are absent, just that the - rows - collection is no longer
working. If you checked - firstChild - you might find that they are
still there. Then again you might find that the rows are gone. It
doesn't matter, once the page in the other frame has unloaded you have
no grounds for expecting a reference to an element in the document from
that frame to be in any way useful.

Ok, couldn't cloneNode be used to basically 'do' this.

I don't think cloneNode is going to help at all as it is a method of the
Node interface and a clone of a Node that belongs to a document will be
a Node that belongs to the same document. only the importNode method of
another document could do the job, and as Lasse pointed out, IE doesn't
support it yet.
On init one just clones the 'skeleton'
On subsequent modification one just clones the required part and
inserts it into the static structure.
IF the above would hold can I than still 'replace' the not required
table coming in on the new page with the 'stored' static one or
would that result in funny behaviour as well.
<snip>

Having used insertNode to clone a Node into a document in frame A for
storage you would then have to use insertNode on the newly loaded
document to put a clone of the stored node into it.

Richard.
 
F

F. Da Costa

Can I just thank you guys, Lasse & Richard, for explaining this 'swampy
matter' to me (and the list).
Learned two things today of which one is to try and be more specific about
my wording re. elements, objects, references etc.

Richard said:
Trying to store a reference to a table is a shortcut to trying to store
the information within that table, probably the best solution is to
extract the required information from the table and store that in a
JavaScript object belonging to frame A. Probably an object customised to
ease the process of restoring/inserting the information to new elements
created in the other frame.
This probably sounds like the only way to go.
So now i'm just left with one question & that is:
What would be the performance penalty when using a self-constructed
(state)object to populate a document (esp) when we start to get into bigger
(2000+ rows) structures.

It would have to put against an increase in traffic plus addirtional drain
on the server, producing full documents (instead of parts thereof)

I'm just putting this forward because I would not have a clue as to the
true processing potential of JS.

Thx again for your troubles, appreciated.

Fermin
 
F

F. Da Costa

F. Da Costa said:
So now i'm just left with one question & that is:
Correction, its actually two:
Am i right in assuming that any HTMLXyzElement created via the
createElement method *belongs* to the document where created and that these
items cannot be relieds upon?
 
R

Richard Cornford

F. Da Costa said:
Correction, its actually two:
Am i right in assuming that any HTMLXyzElement created via the
createElement method *belongs* to the document where created
Yes.

and that these items cannot be relieds upon?

That depends on what you mean by "relied upon". In the context of the
previous discussion in this thread the issues of element ownership would
be identical.

That is going to depend on haw the Object is implemented. On a
reasonably fast PC you can probably create/insert 2000 elements faster
than you can download the HTML that would describe them. But I would
always recommend having a server-side fall-back for this type of thing
anyway and letting the client-side script ease the burden on the server
when that is practical. And that would give you a system that was not
dependent on dynamic DOM support and so cross browser.

JavaScript is an interpreted scripting language so it should not be
expected to be fast but the DOM methods are implemented in native code
and they will be doing the bulk of the work. It is certainly possible to
significantly undermine the performance of a script by coding it
inefficiently and therefor a lot to be gained with efficient code (at
least when performance is an issue).

Richard.
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top