What is meant by "onload=foo(event)"? - javascript

I am new to JS and found this code section:
<body>
<span id="sp1">
<img src="aurora.gif" onload="ev1(event)">
</span>
</body>
As far I understood, the onload attribute gets triggered if the entire HTML Doc finished "loading". But I don't really understand, whats passed to the ev1 function if the onload attribute is triggered. What is event in this case?
Here is the source code

It's hooking up a handler to the image's load event and passing the event object for the event into the handler. The event object exists reliably cross-browser within the context of the onload attribute-style event handler: On IE, it's a global; on Firefox, it's a local within a synthetic function created for the onload handler; on Chrome, I think it's both. :-)
Note that the ev1 function must be a global, which is one of many reasons not to use onxyz-attribute-style event handlers.

img also has onload attribute & is called when when the image has finished loading. Similarly it also have onerror event handler. event represent the event object.
function ev1(e) {
console.log(e)
console.log('Img loaded')
}
img {
width: 200px;
height: 200px;
}
<img src='https://i.redd.it/xbq78cnv2nr21.jpg' onload='ev1(event)'>

This appears to be an attempt pass the Event Object as an argument to a function called ev1.
Instead of using an inline event, the author developer should have used a JavaScript event, like this.
document.querySelector("img").addEventListener("load", event => {
console.log(event);
});
Good luck.

Related

Why isn't document.onload called?

By looking at the output of console.log(document), I find document has these properties:onload=null;onloadstart=null;onloadend=null;onreadystatechange=null; I write the following code:
<html>
<head><title>test</title></head>
<body>
<script>
document.onload=function(){alert("document.onload");};
document.onloadstart=function(){alert("document.onloadstart");};
document.onloadend=function(){alert("document.onloadend");};
document.onreadystatechange=function(){alert("document.onreadystatechange");};
</script>
<div>hello</div>
</body>
</html>
Interestingly, document.onload,document.onloadstart,document.onloadend are never called, while document.onreadystatechange is called twice, why?
Why isn't document.onload called?
First of all the load events (created by the browser) do not bubble (because that's how it is specified):
document.body.onload = function(e) {
console.dir(e.bubbles)
}
So you can only listen for these load events, on the element for which they occur.
And for Document there is no load event listed that will be triggered based on the standard.
readystatechange on the other hand is listed as an event that can happen for document.
You can however for sure listen for load events on the document and the event callback will be called. But that will only happen if you e.g. manually trigger one on document:
const event = new Event('load');
document.onload = function (e) {
console.log('load document')
}
document.dispatchEvent(event);
Or if you emit a load event that bubbles on a descendant:
const event = new Event('load', {bubbles: true});
document.onload = function (e) {
console.log('load document')
}
document.body.dispatchEvent(event);
So why does onload then appear as a property? That's due to the GlobalEventHandlers and Document includes GlobalEventHandlers), and due to event handler IDL attribute, exposing those as on… event properties.
I'm unsure, but try this:
window.addEventListener('load', () => {
alert("document.onload")
})
I only use window onload event, but if I never saw document onload event, just change window to document.
Like I said´, I'm unsure what to do, because the amount of your code, which you showed is to less.
.onload is part of the window object, not for document.
GlobalEventHandlers.onload
The onload property of the GlobalEventHandlers mixin is an event handler that processes load events on a Window, XMLHttpRequest, <iframe> and <img> elements, etc.
And from what i've seen on MDN .onloadstart and .onloadend are used for resources like images, don't know if they are availiable for document/window. GlobalEventHandlers.onloadstart
But I think with onreadystatechange you should be able to emulate the behavior of onloadstart and onloadend.
Document.readyState

load event doesn't work with addEventListener but works with onload property

const body = document.querySelector("body");
body.addEventListener("load", () => {
console.log("test");
});
body.onload = () => {
console.log("test");
};
when i use only addEventListener i don't see the message in the console but if i use onload property or use onload attribute in the html it works
This is because the load event is part of what is called the Window-reflecting body element event handler set.
Basically, these events are also accessible as HTML attributes and IDL attributes on the <body> element, even though the primary target is actually the Window object.
This is done because historically we had to use HTML attributes to set event handlers, and setting the load event in the <body> tag was more "natural". Since then we have gotten far better ways to set up event handlers and we can define clearly that this event fires on the Window object, which is more logical.
However browsers still need to support code that was listening to the onload="" HTML attribute, so this reflection thing has been set up.
Note that it's not just adding a new event listener, the event actually only fires on the Window object, but the handler can be set from the <body>, even overriding the ones already set on the Window object.
window.onmessage = (evt) => console.log("handled a message from Window, is Window the currentTarget:", evt.currentTarget === window);
document.body.onmessage = (evt) => console.log("handled a message from body, is Window the currentTarget:", evt.currentTarget === window);
postMessage("hello", "*");
EventTarget#addEventListener() has no means to do this retargetting, so when you do document.body.addEventListener("load", cb), you are really waiting for an event that will go through the <body> element, but as demonstrated above, the event actually only fires on the Window object.

Calling onload event with more than function call

I have something like this in my html:
<body onload='myjavascriptfunction1()'
I also want to be able, with the same onload event to call 'myjavascriptfunction2() along with myjavascriptfunction1()'. Please, is this possible?
You can do it like this:
<body onload='myjavascriptfunction1();myjavascriptfunction2()'>
or create a function and then call from that function the other functions you want
function myjavascriptfunction1(){
myjavascriptfunction2();
myjavascriptfunction3();
}
Use a generic OnLoad function
<body onload='onLoad()'>
function onLoad(){
myJSFunction1();
myJSFunction2();
}
But a better way would be to subscribe to the onload event using addEventListener
window.addEventListener("load", myJSFunction1, false);
window.addEventListener("load", myJSFunction2, false);
JSFiddle
This keeps your JS separate from your HTML and prevents you from adding the ugly onLoad attribute to the body tag.
Attach Event Listeners rather than defining onload events in the markup
document.body.addEventListener("load", do_something(), false);
function do_something() {
alert("hello universe");
//do something here
}
Refer to Event Listeners documentation for more info. If your event listener has to work on multiple browsers like legacy IE's you might have to define other event listeners like attachEvent. Libraries like jQuery are handy for these needs as you don't have to worry about browser compatibilities.

Bypassing event.stopPropagation

I'm writing a JavaScript add-on (not in jQuery) which starts working when a certain event has been triggered. It works fine on most of the sites, but I encountered problems in sites that use stopPropagation().
Is it possible to bypass this and attach the event anyway?
For standards-compliant browsers, use the capturing phase. For IE, you can capture mouse events by calling setCapture on an element (probably the body). Once you've done your thing, call fireEvent on the event object's srcElement.
How does stopPropagation() get in your way? (Add more description how/on what your add-on works/attaches).
The only thing stopPropagation() does, is to stop the event from bubbling up to the parent element of the element which received the event. Thus the event handlers on the parent aren't called. But multiple handlers for the same event directly on the element are all called.
So... as long as you bind your event-handler directly to the element which the event is first generated on first, you are ok. If you just try to listen for events on e.g. on body and rely on all events bubbling up to you, you are out of luck.
e.g. if you now click on the red div you will get an alert saying sibling handler and one saying inline handleralthough the earlier defined inline-onclick handler calls stopPropagation().
(Note: this sample doesn't handle IE specifics which uses attachEvent() and cancelBubble)
<style type="text/css" media="screen">
#parent1 { background-color: green; width:300px; height:300px }
#test { background-color: red; width:200px; height:200px }
</style>
<div id="parent1">
<div id="test" onclick="javascript:event.stopPropagation();alert('inline handler');"></div>
</div>
<script type="text/javascript">
parent1.addEventListener('click',
function(e) { alert('parent'); },
false
);
test.addEventListener('click',
function(e) { alert('sibling handler'); },
false
);
</script>

Cancel jQuery event handling

I have setup onclick event handler in the following manner:
element.onclick = function() { /*code */ }
Imagine there are event handlers setup using jQuery method bind() or similar handlers.
$('element').bind('click', function(){/*another function*/})
How can I prevent invoking handler defined with jQuery from the handler I have described in the beginning?
NB stopPropagation() and etc. jQuery's methods doesn't work from that function, because it is passed with native event object.
I'm not 100% sure what you're asking but maybe this will help:
You can create a new event object (compliant with W3C DOM) via jQuery's exposed Event constructor:
For example:
element.onclick = function(e) {
var aBetterEventObject = jQuery.Event(e);
// Now you can do what you want: (Cross-browser)
aBetterEventObject.preventDefault()
aBetterEventObject.isDefaultPrevented()
aBetterEventObject.stopPropagation()
aBetterEventObject.isPropagationStopped()
aBetterEventObject.stopImmediatePropagation()
aBetterEventObject.isImmediatePropagationStopped()
}
EDIT: Reading through your question again, I don't think propagation is the problem - you seem to want to cancel an event handler from running within an event handler - I'm not sure this is possible. You could just unbind all handlers (jQuery(elem).unbind('click')) but I don't think that's what you're after...
try to add the following line in the jQuery event handler:
return false;
Following on from JimmyP's answer. I've tried this
$('#x').click( function(e){
alert('hello');
});
document.getElementById('x').onclick = function(){
$('#x').unbind('click');
alert("goodbye");
}
The jQuery event runs once in this example. I don't think you can rely on the order of handlers being invoked however you define them, so I guess you'll have to accept that the jQuery event might fire once. Adding the onclick first does prevent the jQuery event from firing at all but, as I said, I don't think that's reliable.
Jquery has a method for namespacing events. http://docs.jquery.com/Namespaced_Events
You can add, trigger and remove separate functions bound to the same event via namespaces:
$("a").bind("click.custom1",function(){ ... });
$("a").bind("click.custom2",function(){ ... });
$("a").trigger("click.custom2");
$("a").unbind("click.custom2");
As long as you unbind the namespaced event your normal onclick should be unaffected. You may have to bind two separate namespaces to the click event as above if that doesn't work.

Categories

Resources