I was surprised to find the following doesn't appear to work, insofar as the DOMContentLoaded event doesn't fire (this.els is an object of elements).
this.els.stage_ifr.prop('src', 'templates/'+ee.globals.creating+'/item'+this.id);
this.els.stage_ifr[0].addEventListener('DOMContentLoaded', function() {
alert('loaded!');
}, false);
The page loads into the iframe fine, but no callback. The DOM level zero onload, however, works.
this.els.stage_ifr[0].onload = function() { alert('loaded!'); }; //<-- fires
A workaround is to prepare a globally-accessible jQuery deferred object in the parent page and resolve it via a DOM-ready event fired from the page called into the iframe, rather than listening for DOM-ready from the parent.
Paraent page:
dfd = new $.Deferred;
dfd.done(function() { alert("frame page's DOM is ready!"); });
Frame page:
$(function() { window.parent.dfd.resolve(); });
Nonetheless it would be good to know what's up with the first approach...
In the process of answering this question, I discovered the reason your DOMContentLoaded event listener doesn't work. It appears to me that you have two issues.
First, you're trying to listen for the DOMContentLoaded event on the iFrame itself. That isn't an iFrame event. It is a document event. So you have to reach into the iFrame to get the contentWindow and then get the document from that. That leads into the second issue.
Second, when an iFrame is first created, it has a dummy document in it that is NOT the same document as will eventually be there when dynamic content is loaded via the .src attribute. So, even if you did:
this.els.stage_ifr.contentWindow.document
to get the document in the iFrame, it will not necessarily be the right document and thus the DOMContentLoaded event won't fire on it (I've seen this behavior in Chrome).
MDN says that one can listen for the DOMFrameContentLoaded event on the iFrame itself and this will correspond with when the underlying document actually gets DOMContentLoaded. Unfortunately, I can't get this event to work in any browser. So, at this moment, the only work-around I know of is to either trigger the load event from within the iFrame itself where it can listen to its own DOMContentLoaded event (it can call out to the parent window if need be) or to just listen for the load event on the iFrame object and know that it won't fire until resources such as style sheets and images in the iFrame are also loaded.
Anyway, I thought I'd explain some of what was going on with your initial code and offer another solution even though this question was posted more than a year ago (though never answered).
Update:
I've developed a method of tracking DOMContentLoaded for an iFrame loaded with the same origin as its parent. You can see the code here.
After trying different options I found that the following code works for me:
var iframe = document.getElementById("app-frame-id");
iframe.contentWindow.addEventListener("DOMContentLoaded", onFrameDOMContentLoaded, true);
function onFrameDOMContentLoaded () {
console.log("DOMContentLoaded");
};
If your page and the iframe are on the same domain you have to wait for the original page to fire DOMContentLoaded first, then attach a DOMContentLoaded event listener on the iframe's Window (not Document).
Given you have an iframe as follows,
<iframe id="iframe-id" name="iframe-name" src="..."></iframe>
the next snippet will allow you to hook into the iframe's DOMContentLoaded event:
document.addEventListener('DOMContentLoaded', function () {
var iframeWindow = frames['iframe-name'];
// var iframeWindow = document.querySelector('#iframe-id').contentWindow
// var iframeWindow = document.getElementById('iframe-id').contentWindow
iframeWindow.addEventListener('DOMContentLoaded', function () {
console.log('iframe DOM is loaded!');
});
});
This might be more of a hack, but helped me solve a similar issue.
I am listening for onmouseenter of the frame content now.
This event triggers ahead of load (if the user moves the mouse). But as in my case I need the event for initialising a context menu, using the mouse was a precondition anyway.
It even triggers when the frame content changes under the mouse.
Related
I tried to log something after the body element of the page is loaded, but log not appearing in the console. What am I doing wrong?
const body = document.querySelector('body');
function setInitialGradient() {
console.log('Cant see this message on console');
body.style.background = `linear-gradient(to right, ${color1.value}, ${color2.value})`;
cssProperty.textContent = body.style.background + ';';
}
body.addEventListener('load', setInitialGradient);
Use DOMContentLoaded instead
The DOMContentLoaded event will trigger earlier and is usually considered the better option.
[the load event] should be used only to detect a fully-loaded page. It is a common mistake to use load where DOMContentLoaded would be more appropriate.
Set it on the document object.
document.addEventListener('DOMContentLoaded', setInitialGradient);
If you must use the load event
If you must use the load event, you can add a listener to window instead:
window.addEventListener('load', setInitialGradient);
But note:
The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images. This is in contrast to DOMContentLoaded, which is fired as soon as the page DOM has been loaded, without waiting for resources to finish loading.
load event is a property of window neither document nor body. You need to use window instead:
window.addEventListener('load', setInitialGradient);
If you want to use function on load of body or any specific html element, then you'll need to use:
body.onload = setInitialGradient;
// I would use document.onload BTW if it is for body rather than other element
window.addEventListener('DOMContentLoaded', function() { /*put your code here*/ });
alert() is working fine, but when I tried to make a link bold, it is not working.
I think it is because of page is already loaded. Is there any way to do that?
you can do it using jquery:
$("selector").css('font-weight', 'bold');
Using Jquery:
Use ready() to make a function available after the document is loaded:
The ready event occurs when the DOM (document object model) has been loaded.
Because this event occurs after the document is ready, it is a good place to have all other jQuery events and functions.
The ready() method specifies what happens when a ready event occurs.
$(document).ready(function(){
$('selector').css('font-weight','bold');
});
Using Javascript:
The onload event is a standard event in the DOM, while the ready()
event is specific to jQuery. The purpose of the ready event is that it should occur as early as possible after the document has loaded, so that code that adds functionality to the elements in the page doesn't have to wait for all content to load.
window.onload = function () {
all your code goes here.
}
I have an <iframe> that contains a particular webpage. In that iframed webpage, the following Event trigger is setup via jQuery:
console.log($('.myElement').trigger('testEvent'));
This event is triggered every ~20 seconds.
Back on the parent page, when the page first loads, I setup an Event Handler for the event:
$('iframe').load(function(){
console.log("Iframe loaded");
$('iframe').contents().find('.myElement').on('testEvent', function(e) {
console.log("Event Fired!", e);
});
});
So once the iframe is loaded, the event handler is setup.
For some reason, the event handler never runs. The event is definitely being triggered because I see the result of the console.log() in the console. I don't see any errors or anything in the console.
Also I can manually trigger it and see that the handler is working:
$('iframe').contents().find('.myElement').trigger('testEvent');
What am I doing wrong here?
I figured it out. So the parent document and the iframe content document each have their own jQuery instance. Apparently it's not (easily?) possible for one instance of jQuery to listen for events triggered by the other instance of jQuery. My problem in the parent document was this:
$('iframe').contents().find('.myElement').on('testEvent', function(e,data) {});
Here I'm trying to use the the parent jQuery to handle the event. This won't work. I have to use vanilla JavaScript:
document.getElementById('#my_iframe').contentWindow.$('.myElement').on('testEvent'), function(e,data) {});
So here I'm using vanilla JavaScript to get to the iframe contents and then the jQuery from that point on is the iframe's jQuery instance, which is the same instance of jQuery that the trigger happens on.
This worked perfectly!
Due to how some of our pages work, JS can get injected into the page at any point and sometimes this JS closes the current window. The problem is that I need to attach an event listener to the onunload of the window so that a value may be returned from the window to the parent page. But because the window close script may be injected at any point, I can't bind this event to the onload due to how it works so I was hoping to use DOMContentLoaded since that event will trigger before the injected script does.
However in my tests, I cannot get anything to bind to DOMContentLoaded on the parent page where the new window is being created.
Here is an what I am currently working with: Plunker
We only need this to work in Chrome at the moment.
Our current method of doing this works like this (pseudocode):
onButtonClick = function(){
win = window.open(...);
win.onload = function(){
win.onunload = function(){
//Bind some function that will get the window's "return value" and pass it to the parent page
//This will never happen if the window closes itself before the page is done loading
};
};
};
Can I use DOMContentLoaded to accomplish what I want? If so, how do I properly attach it to the window?
Note: I cannot bind the onunload event directly to the window once it is created. It seems to fire the onunload event twice (once when the window opens and once when it closes). You can see this happening if you use the bindOnCreate function in my example.
If you change line 58 from
w.document.addEventListener('DOMContentLoaded', ...)
to
w.addEventListener('DOMContentLoaded', ...)
it works. I'll try to explain what's actually going on under the hood:
When window is opened, it is initially having URL about:blank. You can check this by logging w.location.toString() in onunload event handler (see next step).
Immediately after that the browser loads URL supplied in window.open, thus triggering onunload for about:blank (first time).
Real page with different window.document is loaded into pop-up window, but your event handlers are still listening to the DOM root of about:blank page because you added events to window.document, not window; and right now as we have another URL loaded, window.document is completely different object than one step before.
When you close window, onunload is triggered again (second time) because your onunload event was connected to window.
If you addEventListener for pop-up's window, it receives events from all window.document-s that will be loaded inside that window because of JS event bubbling mechanism.
I hope this answers your questions.
Alternatively, you can send a message from the child window to its opener, rather than let opener to handle child window's unload event. This will be much easier and you don't need to worry about the injection point. Also you can get rid of twice unload event, as Andrew Dunai has already given the reason for this issue.
Here I give a very simple demo, only shows the skeleton of my messaging solution:
parent.html
<button id="open">Open Window</button>
<button id="close">Close Window</button>
<div></div>
<script>
var child;
document.querySelector('#open').addEventListener('click', function() {
document.querySelector('div').innerHTML = '';
child = window.open('child.html', 'child', 'width=600,height=600');
}, false);
document.querySelector('#close').addEventListener('click', function() {
child.close();
}, false);
window.addEventListener('message', function(e) {
document.querySelector('div').innerHTML = e.data;
}, false);
</script>
child.html
<input type="text" value="" placeholder="input something">
<script>
window.addEventListener('beforeunload', function() {
var msg = document.querySelector('input').value;
window.opener.postMessage(msg, '*');
}, false);
</script>
Either you close child window by click its own window's close button, or the button in parent window, the value in child's input will always send to parent and presented.
This is the key approach for one of my side project, and works very well.
My main HTML page does the following:
var popup = window.open(...);
// Wait for popup to load
popup.onload = function() { do_something(); };
popup.location = "new-page.html";
I'd like do_something to be called when new-page.html is finished loading. But what I currently have doesn't work -- do_something is never called.
How can I make this work?
I only care about getting this to work in Firefox 3.5, if that makes things easier.
you could use window.opener.<functionName> and put your notification code within that function on the parent page
Have you tried using the opener object?
http://www.webreference.com/js/tutorial1/opener.html
Or, without messing with the HTML of the child window, from the parent, you can attach a listener on the load event of the iframe. In this solution, i am going to use jQuery for simplicty, but any library or even manual event attachment will do.
In the parent's HTML:
<iframe id="foo"></iframe>
<script type='text/javascript'>
var element = $("#foo");
element.load( function( eventObject ) {
// do something here
} );
// Now that the event listener is attached, we can set the source.
element[0].src = "foo.html";
</script>
Note, I have not tried setting the source first and then attaching the listener, I am not sure if this would be guaranteed to always work. It could happen that the iframe is created/loaded before the load listener is attached, I am not sure. But, by setting the src after the listener is attached, I am sure that the load listener will be called.
Shane
http://www.shanetomlinson.com
http://www.ubernote.com
Try having the doSomething method called in the popup's onload. You can refer back to the parent by using window.opener
In your .html that is loaded you could have a simple one liner at the end that calls a function on the opening window (if it exists)
<script type='text/javascript'>
if (window.opener && window.opener.do_something) window.opener.do_something(window);
</script>