window.onload fails from external JS file

M

Mark Anderson

Hi, I have this in an external JS library:

/////////////////////////
function addMyEvent(){
var obj;
if(document.attachEvent) {
obj = document.getElementsByTagName('img');
for (i=0;i<obj.length;i++) {
obj.attachEvent('ondrag', noDrag);
}
obj = document.getElementsByTagName('a');
for (i=0;i<obj.length;i++) {
obj.attachEvent('ondrag', noDrag);
}
}
}

function noDrag() {
// kill the drag event
return false;
}
////////////////////////

If I call it from the associated web page (no frames/IFrames, etc.
involved) via:

<body onload="addMyEvent();">

It works. If I try the unobtrusive metho and use <body> on the page
and...

window.onload = addMyEvent();

... in the JS library it fails. Have I got the syntax wrong or can only
the calling page use the 'onload' event.

[FWIW, I have to stop drags of images as their SRCs are query URLs and
dragged images get wrong names 'aspscript.jpg'. I provide a download
link for correct naming]

TIA,

Mark
 
M

Mark Anderson

----- Original Message -----
From: "Randy Webb" <[email protected]>
Newsgroups: comp.lang.javascript
Sent: Monday, June 04, 2007 10:24 PM
Subject: Re: window.onload fails from external JS file

Mark Anderson said the following on 6/4/2007 5:05 PM:



That executes the addMyEvent function as soon as it encounters it and
assigns the return value (if any) to the window.onload event handler.
To "fix" it, remove the ():

window.onload = addMyEvent;

Actually, I'd tried this syntax (no bracket) too and no joy. There are
no other libraries, but the existing library has this as well:
///////
// trap Safari /Firefox behaviour
killDrag={
init:function(){
if(!document.getElementById || !document.createTextNode){return;}
// we'll only trap <a> and <img> inside ID 'imageLoc'
killDrag.n=document.getElementById('imageLoc');
if(!killDrag.n){return;}
killDrag.addMyListeners('mousedown',killDrag.suppressDrag,'img');
killDrag.addMyListeners('mousedown',killDrag.suppressDrag,'a');
},
addMyListeners:function(eventName,functionName,elements){
var temp=killDrag.n.getElementsByTagName(elements);
for(var i=0;i<temp.length;i++){
temp.addEventListener(eventName,functionName,false);
}
},
suppressDrag:function(e){
e.stopPropagation();
e.preventDefault();
}
};
window.addEventListener('load',killDrag.init,false);
////////////////

As IE doesn't support these events, I assumed they don't matter but
perhaps they throw an error in IE? However, if so, why does a call from
<body> work with the same functions in the library? I'm stumped.

Mark
 
M

Mark Anderson

dd said:
Is there a reason you want it to
create a GLOBAL variable called i ?

Global? The var 'i' isn't explicitly declared but it is inside a
function - how then is it global? Surely its scope is that of the
containing function:

function addMyEvent(){
var obj;
if(document.attachEvent) {
obj = document.getElementsByTagName('img');
for (i=0;i<obj.length;i++) {
obj.attachEvent('ondrag', noDrag);
}
obj = document.getElementsByTagName('a');
for (i=0;i<obj.length;i++) {
obj.attachEvent('ondrag', noDrag);
}
}
}

What would be more helpful at this point would be any pointers on why my
window.onload call in an external JS file fails.

Regards

Mark
 
L

-Lost

Randy said:
Start removing other parts of the code until it works. Then start adding
them back until it breaks. That is how you find errors/problems and most
people refer to it as "debugging".

Oh, no! Not "de bug ging." Dem come 'round and steal me good tots, me
code suffer large mon.

I hate it when "de bug ging" visit me 'ere. De bugging me!

*runs away screaming from de bugs*

De bugs scare de' caca clean out ah me!

Ya, mon.
 
M

Mark Anderson

Mark Anderson said:
----- Original Message -----
From: "Randy Webb" <[email protected]>
Newsgroups: comp.lang.javascript
Sent: Monday, June 04, 2007 10:24 PM
Subject: Re: window.onload fails from external JS file

Mark Anderson said the following on 6/4/2007 5:05 PM:



That executes the addMyEvent function as soon as it encounters it and
assigns the return value (if any) to the window.onload event handler.
To "fix" it, remove the ():

window.onload = addMyEvent;

Actually, I'd tried this syntax (no bracket) too and no joy. There
are no other libraries, but the existing library has this as well:
///////
// trap Safari /Firefox behaviour
killDrag={
init:function(){
if(!document.getElementById || !document.createTextNode){return;}
// we'll only trap <a> and <img> inside ID 'imageLoc'
killDrag.n=document.getElementById('imageLoc');
if(!killDrag.n){return;}
killDrag.addMyListeners('mousedown',killDrag.suppressDrag,'img');
killDrag.addMyListeners('mousedown',killDrag.suppressDrag,'a');
},
addMyListeners:function(eventName,functionName,elements){
var temp=killDrag.n.getElementsByTagName(elements);
for(var i=0;i<temp.length;i++){
temp.addEventListener(eventName,functionName,false);
}
},
suppressDrag:function(e){
e.stopPropagation();
e.preventDefault();
}
};
window.addEventListener('load',killDrag.init,false);
////////////////

As IE doesn't support these events, I assumed they don't matter but
perhaps they throw an error in IE? However, if so, why does a call
from <body> work with the same functions in the library? I'm stumped.

Mark


Figured it out. IE was choking on this line
window.addEventListener('load',killDrag.init,false);

Changing it to

if (window.addEventListener) {
window.addEventListener('load',killDrag.init,false);
}

.....and using window.onload = addMyEvent; without the () and it works.

Thought I'd post it in case it helps anyne else.

Regards

Mark
 
L

-Lost

Mark said:
Figured it out. IE was choking on this line
window.addEventListener('load',killDrag.init,false);

Changing it to

if (window.addEventListener) {
window.addEventListener('load',killDrag.init,false);
}

....and using window.onload = addMyEvent; without the () and it works.

Thought I'd post it in case it helps anyne else.

You erroneously assume that everyone else does not initiate proper
feature detection routines and/or fails to realize that Internet
Explorer does not adhere to the Gecko DOM, or JavaScript standards.

It is wise to always check for specific features you require. In that
fashion you eliminate having to go through what you did.
 
D

dd

You erroneously assume that everyone else does not initiate proper
feature detection routines and/or fails to realize that Internet
Explorer does not adhere to the Gecko DOM, or JavaScript standards.

I think the JavaScript error saying that IE doesn't understand
addeventlistener would have been the biggest hint in this story. Of
course you can turn off those nasty (helpful) error messages.
 
M

Mark Anderson

dd said:
I think the JavaScript error saying that IE doesn't understand
addeventlistener would have been the biggest hint in this story. Of
course you can turn off those nasty (helpful) error messages.

dd - IE doesn't, as you imply, tell the user where the error lies - "...
the JavaScript error saying that IE doesn't understand addeventlistener
....". It simply gives a non-specific (for the inexpert user) message and
a line number that could be any of the current page or it's libraries,
etc. In this particular case the line number, perhaps due to the code
flow, didn't immediately indicate the exact cause - just there was an
error. Were it was as obvious as you imply, then I wouldn't have needed
to ask!

Thus the observation doesn't help the less experienced JS user reading
this in the archive as it implies they should expect a message from IE
that they just won't see.

I'm not suggesting you meant to be unhelpful with the above advice -
it's just not helpful as written because it assumes knowledge the reader
clearly won't have (or they'd not have the problem).

Nonetheless thanks to you all n/g members for their help. Certainly,
using the 'myfunction;' syntax instead of the normal 'myfunction();' is
an unintuitive step I'd not have guessed.

Regards

Mark
 
M

Mark Anderson

Randy Webb said:
Mark Anderson said the following on 6/4/2007 5:05 PM:



That executes the addMyEvent function as soon as it encounters it and
assigns the return value (if any) to the window.onload event handler.
To "fix" it, remove the ():

window.onload = addMyEvent;

I see now the latter works, but what changes for the sake of a pair of
empty brackets? I think ...

<body onload="myFunct();"> works with the result of myFunct() as it
isn't called until the event fires. Conversely, when using window.onload
= myFunct; in a JS library is telling the browser *ahead* of the
'onload' event, what code to run - in our case a function called
'myFunct' - *when* the event fires. Getting the result of myFunct is
likely meaningless or unusable before the event is triggered.

Ah, I think the O'Reilly JSS Definitive Guide alludes to the use or not
of () on page 393 whilst unhelpfully not explicitly noting the effect
of the inclusion or not (). This isn't intuitive to learn as all basic
JS references tell you the function construct is functName() - i.e. the
brackets are always needed.

But, as a good case in point about references, the same book's 25 page
chapter on Function doesn't cover this (it does tell you want the
brackets do, not what happens without), referring only to a similarly
uninformative mention of the Function operator '()' on Ch 5, page 81.
The above issue isn't pertinent to the Ch 5 reference and the Ch 8
*assumes* the issue is covered already (in Ch 5 - it isn't) and the
error then recurses right through a generally excellent reference (I'm
sure I could find the same error - or worse - in most other JS books).

What JS references/books ought to add when describing functions is that
if a function is placed on the right side of an = without the () then
the left side (attempts to) become the right-side function. This,
simplistically,

var myNum = 2;
function myFirst(data) {
return data;
}
function mySecond(data) {
data = data * 2;
return data;
}
alert(myFirst(myNum)); // 2
myFirst = mySecond;
alert(myFirst(myNum)); // 4
myFirst = mySecond();
alert(myFirst(myNum)); // Code errors as last line isn't valid code

The explanation helps both ways; ff you forget the () when you should
use them, then you are assigning the function (i.e. you get no immediate
result, with them you are assigning the result. I'm sure an expert could
explain this more elegantly, but without placing something like this in
any explanation of how to use functions, it's a stretch to assume a
learner will know how to assign a function to something later in their
JS use. IMO, anyway!

A muddying factor in my original problem is the need for window.onload
to attach events is more due to IE failing - i.e. it can't use the DOM
..addEventListener() function. Still, sadly IE is everywhere so the more
ugly attachment method is needed, even by less experienced JS users.

Perhaps an explanation (better than mine!) of this () issue might be a
<FAQENTRY>? In the meantime, I'm sure I'll be returning to this post as
reference ere long, when I've forgotten and got it wrong again.

Thanks

Mark
 
D

dd

On Jun 8, 2:14 pm, "Mark Anderson"
Perhaps an explanation (better than mine!) of this () issue

The simplest explanation is that the <body onload="funcname()"> is
HTML and the function is a string. It's specifying the javascript
string to be executed onload. It could be something like <body
onload="myloadedflag=true;">

The other code, is pure Javascript. It's inside a script block. In
that case, you're giving the onload a pointer to a function:

window.onload=myfunction;

You could also use an anonymous function:

window.onload=function(){alert('loaded');}

These are the effectively the same.

By adding the () at the end, you're telling it to call that function
now. The only way that could work is if the function you're calling
returns another function ptr.
 
R

Randy Webb

Mark Anderson said the following on 6/8/2007 8:14 AM:
I see now the latter works, but what changes for the sake of a pair of
empty brackets? I think ...

What changes is *when* the function gets executed. If this gives you a
headache, try figuring out what effect (), and the lack of them, has on
a setTimeout call.
<body onload="myFunct();"> works with the result of myFunct() as it
isn't called until the event fires. Conversely, when using window.onload
= myFunct; in a JS library is telling the browser *ahead* of the
'onload' event, what code to run - in our case a function called
'myFunct' - *when* the event fires. Getting the result of myFunct is
likely meaningless or unusable before the event is triggered.

They both know ahead of time what to execute. <body onload tells the
browser as soon as it encounters it what it is going to execute. Neither
of them execute until the page finishes loading. Want another headache?
<body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>

Without testing, which alert will you see, and why?

<snip>
 
M

Mark Anderson

Randy Webb said:
Mark Anderson said the following on 6/8/2007 8:14 AM:
"Randy Webb" <[email protected]> wrote in message
[snip]
They both know ahead of time what to execute. <body onload tells the
browser as soon as it encounters it what it is going to execute.
Neither of them execute until the page finishes loading. Want another
headache? <body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>

Without testing, which alert will you see, and why?

A message "Window onload", as the script loads after the HTML is parsed.
I'd assume that if the script were moved the page's <head> section then
you'd see "Body onload" as the <body> onload attribute is read/processed
after the inline script. With an external library script, I assume the
same applies unless the library is slow to load and is processed after
the <body> tag is read - or is execution of the latter delayed until all
external libraries called from the <head> have loaded? Indeed where
would the learner look to find the 'rule' on the latter?

Regards

Mark
 
M

Mark Anderson

dd said:
On Jun 8, 2:14 pm, "Mark Anderson"

The simplest explanation is that the <body onload="funcname()"> is
HTML and the function is a string. It's specifying the javascript
string to be executed onload. It could be something like <body
onload="myloadedflag=true;">

The other code, is pure Javascript. It's inside a script block. In
that case, you're giving the onload a pointer to a function:

window.onload=myfunction;

You could also use an anonymous function:

window.onload=function(){alert('loaded');}

These are the effectively the same.

By adding the () at the end, you're telling it to call that function
now. The only way that could work is if the function you're calling
returns another function ptr.

Thanks. I see now problem here is that the learner in this scenario will
assume a lack of result is due to an error in the function they're
calling rather than the way the function's called. I think I've learned
this issue now so I won't forget. I am surprised though that the
books/references I was consulting back before I asked here didn't cover
this issue, from a learners perspective. I guess it's the classic trap
of being so obvious to the expert author as to not warrant explicit
explanation.

If nothing else hopefully this thread in the n/g archive will help
others save the time I lost pondering over this last week.

Thanks again for the help!

Mark
 
R

Randy Webb

Mark Anderson said the following on 6/10/2007 9:29 AM:
Randy Webb said:
Mark Anderson said the following on 6/8/2007 8:14 AM:
"Randy Webb" <[email protected]> wrote in message
[snip]
They both know ahead of time what to execute. <body onload tells the
browser as soon as it encounters it what it is going to execute.
Neither of them execute until the page finishes loading. Want another
headache? <body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>

Without testing, which alert will you see, and why?

A message "Window onload", as the script loads after the HTML is parsed.
I'd assume that if the script were moved the page's <head> section then
you'd see "Body onload" as the <body> onload attribute is read/processed
after the inline script. With an external library script, I assume the
same applies unless the library is slow to load and is processed after
the <body> tag is read

No matter where you put the window.onload, it will take precedence -
overwrite - the <body onload> code. Test it :) Whether it is in the head
section, body section, external file, the window.onload will fire and
stop the body onload from firing.
- or is execution of the latter delayed until all external libraries
called from the <head> have loaded?

Neither window.onload nor body onload will fire until the page has
completely loaded including any, and all, external files. Whether they
are images, css file, js files, any external file (even an iframe file).
Indeed where would the learner look to find the 'rule' on the latter?

It is probably in a spec somewhere, I honestly don't know. I learned it
by testing and testing.
 
D

dd

Neither window.onload nor body onload will fire until the page has
completely loaded including any, and all, external files. Whether they
are images, css file, js files, any external file (even an iframe file).

FYI Randy, there's been some work done on finding a better
onload than the standard one which as you know waits for all
page assets to load. This new method will "fire" when there's
only images left to load (i.e. the DOM is structurally
complete and scriptable):

http://dean.edwards.name/weblog/2006/06/again
http://www.thefutureoftheweb.com/blog/adddomloadevent
 
M

Mark Anderson

Randy Webb said:
[snip]
Want another headache?
<body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>

Without testing, which alert will you see, and why?

A message "Window onload", as the script loads after the HTML is
parsed. I'd assume that if the script were moved the page's <head>
section then you'd see "Body onload" as the <body> onload attribute
is read/processed after the inline script. With an external library
script, I assume the same applies unless the library is slow to load
and is processed after the <body> tag is read

No matter where you put the window.onload, it will take precedence -
overwrite - the <body onload> code. Test it :) Whether it is in the
head section, body section, external file, the window.onload will fire
and stop the body onload from firing.

So, window.onload is always taking precedence? I can't replicate that.
Following used IE v6 patched to date on XP(SP2) patched to date.

Test #1:
<html>
<head>
</head>
<body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>
</body>
</html>
....result message "Window onload".

Test #2:
<html>
<head>
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>
</head>
<body onload="alert('Body onload')">
</body>
</html>
....result message "Body onload" [sic]. Here, window.onload isn't taking
precedence.

From your earlier post I have assumed both code version should result in
"Window onload". FWIW, if I substitute an external library for the
inline script the results are still the same.

Regards

Mark
 
V

VK

[snip]
Want another headache?
<body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>
Without testing, which alert will you see, and why?
A message "Window onload", as the script loads after the HTML is
parsed. I'd assume that if the script were moved the page's <head>
section then you'd see "Body onload" as the <body> onload attribute
is read/processed after the inline script. With an external library
script, I assume the same applies unless the library is slow to load
and is processed after the <body> tag is read
No matter where you put the window.onload, it will take precedence -
overwrite - the <body onload> code. Test it :) Whether it is in the
head section, body section, external file, the window.onload will fire
and stop the body onload from firing.

So, window.onload is always taking precedence? I can't replicate that.
Following used IE v6 patched to date on XP(SP2) patched to date.

Test #1:
<html>
<head>
</head>
<body onload="alert('Body onload')">
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>
</body>
</html>
...result message "Window onload".

Test #2:
<html>
<head>
<script type="text/javascript">
window.onload=function(){alert('Window onload')}
</script>
</head>
<body onload="alert('Body onload')">
</body>
</html>
...result message "Body onload" [sic]. Here, window.onload isn't taking
precedence.

From your earlier post I have assumed both code version should result in
"Window onload". FWIW, if I substitute an external library for the
inline script the results are still the same.

body onload="something();"

is equal to:

window.onload = function(){ something(); }

so as far as my humble mind goes it has to be a race condition here,
like:

/* 1 */ window.onload = foo();
/* 2 */ window.onload = bar();
/* 3 */ window.onload = function(){ something(); };

The winner above is the last anonymous function of course, but if all
three functions are coming at different time from different
locations: maybe some UAs are going nuts of it?
 

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
474,472
Messages
2,571,834
Members
48,802
Latest member
shadowoftheunknown
Top