PDA

View Full Version : When is it ok to call .innerHTML property?


WA
04-28-2003, 08:16 AM
Hi:
This is more a question on browser compatibility I guess, but is the .innerHTML property generally writeable as soon as the element in question is defined? For example:

document.write('<div id="test"></div>')

testObj.innerHTML="Some text"

I ask this because I remember that in IE4, the .innerHTML can only be called after the page has loaded (onload), though this no longer seems to be the cause in new browsers of IE and NS6+. Is there some guideline to when the .innerHTML property of an element becomes available+writeable in the various browsers?

I know simply calling it on page load takes care of the above ambiguity, but I really wish to call it as soon as possible without tripping up some browsers.

Thanks,

brothercake
04-28-2003, 12:10 PM
The last time I tried something like that it only worked in IE6 - not mozilla; actually I thought it was supposed to be like that and that IE6 was simply being, well, IE-like.

Either way - never rely on being able to read or write-to properties of rendered objects until the entire document has rendered - so a statement at the very end of the <body> should be okay, but an onload attachment would be best.

WA
04-28-2003, 12:27 PM
To be safe I guess it's best to simply execute .innerHTML after the page loads. The problem is that I'm creating a script that could be invoked multiple times on the page; to not have one window.onload cancel the other out seems to be a challenge. For example, I understand I could use syntax like:

window.addEventListener("load", dothis, false) //NS 6
window.attachEvent("onload", dothat) //IE5

But what about the other browsers? Is there a general technique to have indepedant scripts all access window.onload without conflicts? I need a solution that doesn't require tampering with the rest of the page in any way (ie: do something like window.onload="loaded=yes", and have scripts check this variable etc).

Thanks,

liorean
04-28-2003, 01:57 PM
Preparatory code:
Object.prototype.hasProperty=function(sProperty){
return (typeof this[sProperty]!='undefined'?true:false);
}

Object.prototype.getProperty=function(sProperty){
return (this.hasProperty(sProperty)&&this[sProperty]);
}

Object.prototype.getMethod=function(sMethod){
return (this.getProperty(sMethod) instanceof Function?
this[sMethod]:
function(){});
}

Function.prototype.runAfter(fnAdditionalFunction){
this();
fnAdditionalFunction();
}Then do this:window.getMethod('onload').runAfter(fnEventHandler);

brothercake
04-28-2003, 02:45 PM
Originally posted by WA
But what about the other browsers?
Well actually addEventListener is supported in Opera 7 and Safari as well, but as a method of document, not window. However document.addEventListener('load' ... doesn't work in any browser, so for window onload, that method does only work for mozilla after all.

But there are other ways - have a look at this http://www.codingforums.com/showthread.php?s=&threadid=18736#post94186

beetle
04-28-2003, 03:15 PM
Well, from what I've read, there is an unspecified amount of time between writing serialized HTML, and the deserialization of that HTML into the node tree. It's probably dependant on quantity of HTML and PC speed.

liorean -- nice solution for the multiple onload issue :thumbsup:

liorean
04-28-2003, 04:22 PM
Problem is, it won't work. It will execute the event handlers on the spot instead of replace them with the new one, that will execute them both. I just realised my error on that point - you'll have to do it this way instead:

// Revised runAfter
Function.prototype.runAfter=function(fnAdditionalFunction){
var
fnCurrentFunction=this
return function(){
fnCurrentFunction();
fnAdditionalFunction();
}
}

// Revised action to take
window.onload=window.getMethod('onload').runAfter(fnEventHandler); // where fnEventHandler is the new event handler.

Brothercake, Beetle, JKD or any other that might know this: is there a way to get either assignment to/replacement of this to work, or to get assignment to the return value of a function to work? Or, alternatively, is there any way to mutate a function? (modify it, not replace it)

beetle
04-28-2003, 04:32 PM
What do you have in mind?

liorean
04-28-2003, 04:47 PM
// Oh, just this to work:
[object anyObject].getMethod([string anyString]).runAfter([function anyFunction]);
//Where
Function.prototype.runAfter=function(fnAdditionalFunction){
var
fnCurrentFunction=this;
this=function(){
fnCurrentFunction();
fnAdditionalFunction();
}
return this;
}
// Or the equivalent using a mutation of the function instead
// of assignment to the result of the getMethod method and
// the replacement of this with a new function.If this were Scheme (or any other LISP), that would be a possible action, but for JavaScript I'm not so sure.

beetle
04-28-2003, 05:07 PM
I don't think you can do that w/o an assignment operator on the calling end.

Not 100% sure tho.

liorean
04-28-2003, 08:02 PM
Then I'll write my own Reference object to handle this...// Reference object Constructor
function Reference(oParent, sMember){
if(!(this instanceof Reference))
return new Reference(oParent, sMember);
var
oParent=oParent,
sMember=sMember;
this.type=typeof oParent[sMember];
this.property=this.type!='undefined';
this.method=this.type=='function';
this.assign=function(vValue){
return(this[sMember]=vValue);
}
this.runAfter=function(fnSecond){
var
fnFirst=oParent[sMember];
return (oParent[sMember]=this.method?
function(){
fnFirst();
fnSecond();
}:
fnSecond)
}
return this;
}

Object.prototype.getChildRef=function(sProperty){
return new Reference(this,sProperty);
}

// Calling Elvis
window.getChildRef('onload').runAfter(fnEventHandler);A bit large, not too handsome, but it does what it's supposed to do. The reference object could be handly for much - especially if you could input an object and get a reference back.

JavaScript lacks parent-object references or writing that would be easy. As it is now, you would have to climb from the window object until you found it, having to make certain that you don't happen to get into an endless recursion of for example window['window']['window']['window'] etc - you would have to test the next object you recur on towards the set of objects that you have already visited. Not to speak of the possibility that your object isn't enumerable and thus the reference cannot be found, even though you could enter it manually.

beetle
04-28-2003, 08:31 PM
For rigging an onload setup like this, I'd probably just push items onto a stack and loop through it onload, calling each one in sequence.

liorean
04-28-2003, 08:49 PM
I coded that for reusability, not effectivity - your approach is the one I'd have used two years ago, when I didn't care as much for the finer points of JavaScript as I do now.

Next project - bringing LISP concepts into JavaScript.

WA
04-28-2003, 10:36 PM
Great posts guys! It'll definitely provide me with lots of ideas on getting around this problem. FYI the script I'm working on is based on OOP like brothercake's tooltip script, so I really want it to be as self encapsulating as possible. It seems the window.onload issue is just one of those annoying wrenches in the OOP's spokes, like running setTimeout/setInterval etc (which I've resolved).

Thanks,

jkd
04-28-2003, 10:37 PM
Originally posted by liorean
Next project - bringing LISP concepts into JavaScript.

Bah, you could just wait for JS 2.0 and get some real OO functionality. :)
I assume you've looked the specs... a move away from prototypes to a more classical OO language (but still has what I like about JS 1.X too).

And LISP is just a functional language, right? You can do functional programming in Javascript if you really wanted to.

A lot of this thread reminds me of discussions I had with Alex Vincent a while back... very educational, though I doubt they still exist on the WA archives.

As for setting multiple onload handlers with using DOM methods... I think I'd still prefer a stack, much like beetle said.

I mean, something as simple as:

window.loadListeners = [];
window.addToOnload = function(func) {
loadListeners.push(func);
}
window.onload = function() {
while (loadListeners.length != 0)
loadListeners.pop()();
}

would be adequate...

beetle
04-28-2003, 10:50 PM
Nice jkd -- exactly what I had in mind :thumbsup:

* wait....did we just agree on something? * :eek:

j/k :p

jkd
04-29-2003, 12:08 AM
Originally posted by beetle
* wait....did we just agree on something? * :eek:

* feels a need to edit the post ;) *

WA
04-29-2003, 12:59 AM
I just recalled another potentially useful property in all of this:

document.readyState

It only works in IE, but since it does even in IE4, I can use it to just continously probe whether the page has loaded to excecute my window.onload function(s).

Is there a NS6+ equivilant of the above property?

liorean
04-29-2003, 04:31 PM
Originally posted by jkd
Bah, you could just wait for JS 2.0 and get some real OO functionality. :)
I assume you've looked the specs... a move away from prototypes to a more classical OO language (but still has what I like about JS 1.X too).
JavaScript already has real OO. What is added, is just classical inheritance and semi-static types. (And a bit more - yes, I've read the specs.) It might be more C++/Java like, but it sure isn't more OO for that. What prototyped inheritance does compared to classical inheritance is basically to merge the constructor and the object template and do away with the destructor in favor of dynamic memory allocation and garbage collecting.And LISP is just a functional language, right? You can do functional programming in Javascript if you really wanted to.LISP is the CONCEPTS behind a certain way of structuring a programming language - if a language exhibits those concepts, it IS a LISP language. The LISP features that I were more interested in, were the ability to do dynamic change of the code, to take a variable and change it, or to take a function and change it. Higher order programming is a LISP concept, and does for functional languages what object orientation does for procedural languages - it makes code reuse easier and structures the language. There are of course powerful object orientation features added in most modern LISPs, but they are not as important in the language structure as they are in procedural languages.A lot of this thread reminds me of discussions I had with Alex Vincent a while back... very educational, though I doubt they still exist on the WA archives.

As for setting multiple onload handlers with using DOM methods... I think I'd still prefer a stack, much like beetle said.I think I'd agree on that - but only because of the lack of ability to mutate a function. My Reference object was just a way to add the overall ability to send a reference instead of a value.I mean, something as simple as:

window.loadListeners = [];
window.addToOnload = function(func) {
loadListeners.push(func);
}
window.onload = function() {
while (loadListeners.length != 0)
loadListeners.pop()();
}

would be adequate...
Yes, it would, but I wanted to construct something useful for the general situation instead of optimised for the specific task at hand.

beetle
04-29-2003, 04:52 PM
Originally posted by liorean
..but I wanted to construct something useful for the general situation instead of optimised for the specific task at hand. We're not being an architecture astronaut (http://www.joelonsoftware.com/articles/fog0000000018.html) now, are we? ;)

Many current browsers already support event adding/attaching -- and that support will only increase.

jkd
04-29-2003, 07:34 PM
Originally posted by liorean
JavaScript already has real OO.

I haven't had a formal class on OO, so I'm not going to argue. But without classical inheritance, many of things I consider OO can't effectively be done.

i.e. calling this() inside the constructor, or super() to call the parent class's constructor.

liorean
04-29-2003, 09:02 PM
Those are not inherent of classical inheritance, nor are they in any way impossible in prototyped inheritance. They just aren't existent in the ECMAScript implementation of prototyped inheritance.

I would personally prefer addition of inheritance climbing (bidirectionally), member climbing (parent object also, not only children as right now), and self referencing to the prototyped inheritance model of today than adding classical inheritance with those features as an alternative inheritance. (Running the two systems in parallel is not a good option in any case.)

All features of classical inheritance can be included in prototyped inheritance (including partial and multiple inheritance), while the other way around isn't true. That's why I prefer prototyped.