Check if an element and its children have been loaded - javascript

I know the .load() function in jQuery, and how to use the callback function with that... but is there a way to check if an element has been loaded using an if statement?
My reasoning... I want to set an interval and check if an element and all it's children have been fully loaded.
var load-interval = setInterval(function(){
if($('#content').hasBeenLoaded){
//do stuff
}
}, 1000);

var $content = $('#content');
var intervalId = setInterval(function(){
if(!$content.is(':empty')){
//do stuff
clearInterval(intervalId);
}
}, 1000);
Just note that elements that contains only text nodes considered to be non empty by the spec:

During initial page load, your DOM elements are progressively created as the file is parsed, but image assets are typically loaded asynchronously as they're referenced.
So, as your page loads, the parser will come across the element <div id="mycontent">.
This element will be created immediately, and then its children, and then eventually the closing tag for that div will be found. At that point you could consider that the DOM itself is "loaded" for that element.
The simplest way to execute something then is to put it in a <script> tag immediately after that closing tag.
If you also want to wait for the image assets to load, then this is still the place to put it. You can look for all <img> tags within the previously loaded div, and register onload callbacks, e.g.
<div id="mycontent">
lots of DOM, including image tags
</div>
<script>
(function() {
var div = document.getElementById('mycontent'); // guaranteed to exist
var imgs = div.getElementsByTagName('img');
// put image load detection code here - exercise for the reader
})();
</script>

Related

Does anyone know a way to print the loaded page HTML after DOM is completed?

I'm looking for a way to read the source code of a page after it finished loading and inspect the code to see if it contains a specific text.
I found this reference but this only returns the text visible in the page and not the whole HTML code.
For instance, if the html source code is:
<html>
<header>
<header>
<body>
<p> This is a paragraph</a>
<body>
</html>
I want the script to print exactly the same thing.
Your help is appreciated.
I think you are over-complicating this problem. You don't need to "print" the page's HTML or "inspect the code".
In a comment, you said:
Check if page contains an iframe [and] Display a message if the iframe is found
You can just use DOM traversal functions to examine the DOM.
Try something like this:
window.addEventListener('load', function() {
if(document.getElementsByTagName('iframe').length){
console.log('Found an iframe');
}
});
Or with jQuery:
$(function() {
if($('iframe').length){
console.log('Found an iframe');
}
});
That's so simple, you can use this method to run a script after a page is fully loaded window.onload
function load(){
console.log(document.getElementsByTagName('html')[0].innerHTML);
}
window.onload = load;
For further explanations, check this post
Do like this, call this function on load
Fiddle Demo
function printBody() {
// store oiginal content
var originalContents = document.body.innerHTML;
// get the outer html of the document element
document.body.innerText = document.documentElement.outerHTML;
// call window.print if you want it on paper
window.print();
// or put it into an iframe
// var ifr = document.createElement('iframe');
// ifr.src = 'data:text/plain;charset=utf-8,' + encodeURI(document.documentElement.outerHTML);
// document.body.appendChild(iframe);
// a small delay is needed so window.print does not get the original
setTimeout(function(){
document.body.innerHTML = originalContents;
}, 2000);
}
Src: Print <div id=printarea></div> only?
Assuming that by 'print' you don't actually mean to transfer it to a paper copy, you can add some script like:
window.addEventListener('load', function() {
var content = document.documentElement.innerHTML,
pre = document.createElement('pre'),
body = document.body;
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
});
What this does, step by step is:
window.addEventListener('load', function() > Wait for the page to be fully loaded and then execute the function
content = document.documentElement.innerHTML > store the actual page source in the content variable (document.documentElement refers to the 'root'-node, usually <html> in html documents
pre = document.createElement('pre') > create a new <pre>-element
body = document.body > create a reference to the <body> element
pre.innerText = content > assign the HTML-structure we've stored earlier as text to the <pre>-element
body.insertBefore(pre, body.firstChild) > put the <pre>-element (now with contents) before any other element in the body (usually on top of the page).
This leaves you with the entire source (as it was before creating the <pre>-element containing the source) on top of you page.
Edit: Added <iframe> workflow
It was not clear to me you actually wanted to target an <iframe>, so here's how to do that (using a naive approach, more on that further on):
window.addEventListener('load', function() {
var iframeList = document.getElementsByTagName('iframe'),
body = document.body,
content, pre, i;
for (i = 0; i < iframeList.length; ++i) {
content = iframeList[i].documentElement.innerHTML;
pre = document.createElement('pre');
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
}
});
why is this approach naive?
There is a thing called Same-Origin-Policy in javascript, which prevents you from accessing <iframe>-content which if the contents do not originate from the same domain as the page containing the <iframe>.
There are several ways to take this into consideration, you could wrap the inside of the for-loop in try/catch-blocks, though I prefer to use a more subtle approach by not even considering <iframes> which do not match the Same-Origin-Policy.
In order to do this, you can swap the getElementsByTagName method with the querySelectorAll method (please note the compatibility table at the bottom of that page, see if it matches your requirements).
The querySelectorAll accepts a valid CSS selector and will return a NodeList containing all matching elements.
A simple selector to use would be
'iframe[src]:not([src^="//"]):not(src^="http")' which selects all iframe with a src attribute which does not start with either // or http
Disclaimer: I never use a <base>-tag (which changes all relative paths within the HTML) or refer to the current website using a path containing the domain, so the example CSS-selector does not consider these aberrations.
Can you use :not()
IE9 or better
Can you use document.querySelector(All)
IE8 or better (in order to use with :not(), IE9 or better)
hover/click the boxes above to show the spoiler

Find out content has fully loaded after adding said content through Javascript

I'm implementing (through pure JavaScript) something like facebook's message loading. Meaning that if you scroll to the end of the page, new (HTML) content is loaded and added to the end of the page. I get this extra content through Ajax. But when I add this (HTML) to the page, it could mean the page has to load extra images. Is there a way I can figure out when the page has finished loading everything, so including all the new images?
You can add the load event (https://developer.mozilla.org/en-US/docs/Web/Events/load) to the appended elements:
function LOADER_FUNCTION(e) {
console.log("LOADED", e.target);
}
var element = document.querySelector('#parent');
for(i=0; i<element.childNodes.length; i++) {
element.childNodes[i].addEventListener('load', LOADER_FUNCTION);
}
This will call the LOADER_FUNCTION function when the content within that element is ready. Oddly this doesn't seem to work when attached to the parent.
Edit:
Here is a working example. Although this example is not using Ajax (mainly due to CORS issues) it should work under the same conditions. I've used innerHTML to set my DOM in order to demonstrate that this event is not limited to createElement -> appendChild:
(function(){
// This Code Runs after DOMContentLoaded
var element = document.getElementById('parent');
function LOADER_FUNCTION(e) {
document.querySelector('.status').innerText = ("LOADED " + e.target.tagName);
console.log("LOADED", e.target);
}
element.innerHTML = "<img src='http://i.imgur.com/OfSN9oH.jpg'>";
for(i=0; i<element.childNodes.length; i++){
// Attach new event handler
element.childNodes[i].addEventListener('load', LOADER_FUNCTION);
}
})()
<div class='status'></div>
<div id="parent"></div>
Edit 2:
For nested children in append/innerHTML use element.querySelectorAll('*');
https://jsfiddle.net/bckpL9k6/1/

My code gives me an error message: GetElementById() is null or not an object

I have this js code:
var id = document.getElementById("myDiv").getAttribute("data-id");
et="Your Message Here";
el="http://x2.xclicks.net/sc/out.php?s="+id+""
sl=new Array();
sn=new Array();
a="</a>"; af="<a target='_blank'";
function dw(n) {document.write(n,"\n");}
function showLink(n,s,b){
if(!s) {s='anc'}
if(!b) {b=''}
else {b="&b="+b}
ast = af+" class='"+s+"' href='"+el;
n = n-1;
if(sl[n]&&sl[n]!="") {
dw(ast+"&o="+sl[n]+b+"'>"+sn[n]+a)
} else {
dw(ast+b+"'>"+et+a)
}
}
Which I load in my header.php like this:
<script type="text/javascript" src="<? bloginfo('template_url'); ?>/js/trf.js"></script>
The problem is that although this is correct:
var id = document.getElementById("myDiv").getAttribute("data-id");
I get this error:
getElementById() is null or not an object
Ady Ideas why?
Do I need to declare a document ready or something?
Do I need to declare a document ready or something?
Yes, exactly. Before the document is ready (ie all tags are parsed to DOM elements), you won't be able to get elements by id. This would only work for elements above your script tag, which are already parsed. Moving the script inclusion from <head> before the end of </body> would help. Alternatively you'll need to use one of the various DOMContentLoaded or onload events, which unfortunately are not cross-browser supported. I recommend to search for a good snippet or use a library.
Assuming you're loading that script in the <head> of your document, you are trying to get an element by ID when that element is not yet loaded into the DOM.
You will need to wait for your document to be ready (via onDOMContentLoaded, window.onload, or any other way of deferring until rendering is complete) in order to access that element by ID.
I would try wrapping it in a $(document).ready. More than likely you're just trying to access it before the DOM is ready
You're loading the script in the header, which means that the script is being loaded before the rest of the document. Inside the script, you're calling document.getElementById straight away, and since the rest of the document hasn't finished loading the chances are extremely high the element you're after won't exist yet.
You need to delay running that part of the script until the document is fully loaded. Wrap that part of the script in a function, and call it during the body.onload event.
As an example (there are other ways to achieve the same result):
window.document.onload = function(e){
var id = document.getElementById("myDiv").getAttribute("data-id");
// Now you have the id and can do whatever you want with it.
}

jQuery get reference to calling script tag

I'm not sure the title of question is all right, as well as how much my question is valid.
Here is scenario:
// HTML
<script src="/script.js" data-app="app.js" />
// script.js
$(function () {
var script = // ???
});
Inside the js code, I want to get reference to original tag, the one who initialized the loading on "/script.js", so I'm able to check the data-app attribute.
Is that possible?
$('script').last().data('app');
Note that this may not be in a DOM ready block. The only place where you can access the current script tag is when it executes for the first time. An async callback such as the DOM ready event would not qualify for this. You can simply store the value in a variable though and then use it from inside your event:
(function() {
var app = $('script').last().data('app');
$(document).ready(function() {
// do stuff
});
})();
You can enumerate the scripts in document.scripts and recognize yours with its src property.
I don't think that there is a "proper" way to get your tag. However, in theory, when your script runs the corresponding tag should be the last one inserted into the document. So putting code like this into script.js works:
var child = document;
while (child && child.localName != "script")
child = child.lastChild;
if (child)
alert("My script tag: " + child);
You will need to run this code when the script loads and remember the script tag if you need it after the initial load.
document.scripts[document.scripts.length-1].src
i don't know what browser support it (IE and chrome, yes)

Waiting for element load after page has loaded

I have a function that loads a SVG Dom from a file. Currently, it creates an embed element and places it in the document, then waits for it to load with an onload event. Apparently, however, onload isn't called for elements placed in the document after the page has loaded. Is there a way that I can register a function to be called after the element has finished loading?
This is what I have:
function loadSVG(svgFilename, callback)
{
// Loads data from an svg file
// loadSVG(
// svgFilename, // The path to the file to load
// callback // The function to be called with the
// // SVG document once it loads.
// );
var embed = document.createElement("embed");
embed.src = svgFilename;
embed.onload = function() // Doesn't get called because page has already loaded
{
var doc = embed.getSVGDocument();
document.getElementById("SVGLoader").removeChild(embed);
callback(doc);
};
document.getElementById("SVGLoader").appendChild(embed);
}
I figured out the problem, I was loading the SVG document in a div tag that was hidden with style="display:none". For some reason, the browser didn't load the embed when it was in this tag. When I removed the style attribute, the onload event fired the way I expected it to.
Relevant: How to check if an embedded SVG document is loaded in an html page?
If you have control over the SVG document, could you not add a script in it that calls a function in the browser window?
Or, as the answer to that question suggested, polling to see if the SVG document has finished loading.

Categories

Resources