Can't affect divs with javascript when using node.js? - javascript

I'm probably doing something obviously wrong but I'm using node.js and I have a javascript file linked properly (alert("hello"); works). But I can't affect anything with the DOM. Simple example:
jade:
doctype html
html
head
link(rel='stylesheet', href='/stylesheets/styles.css')
script(src='/javascripts/script.js')
body
block index_block
div#divClassName
stylus:
#divClassName
background-color red
width 200px
height 200px
js:
alert("hello");
var div = document.getElementById("divClassName");
div.style.backgroundColor = "green";
The box remains red. Why? Thanks.

Since your script is ran before the HTML has been read, the div variables returns undefined since no such element exists at the time your script is executed. Wrapping your JS in a function onload of the document allows you to defer execution until the document has been fully loaded.
window.onload = function(){
alert("hello");
var div = document.getElementById("divClassName");
div.style.backgroundColor = "green";
}

Related

Order of self-invoking function in page load events - javascript/html

I'm looking to find out the order at which a self-invoking js function takes place in terms of the order of events in a page load. I've been googling all over for an answer to this but haven't found anything definitive.
And as for what this actually applies to, I'm adjusting the height of an outer element based on the height of one of it's inner elements (which will vary depending on length of text and screen width)
var text_elem = document.getElementById('text_elem');
var textElemHeight = text_elem.offsetHeight;
var newBkgdHeight = 96 + textElemHeight;
document.getElementById('background').style.height = newBkgdHeight + "px";
as of now this block is being executed in a self-invoked function as opposed to an onload event since with an onload event there's a weird effect where the height adjusts a second or 2 after the page has loaded, but just wanted to be sure that using a self-invoked function is safe and that there's no chance of the code within it being executed before the HTML DOM loads.
EDIT:
Just as a note, this is working properly using a self-invoking function or IIFE, I just want to make sure it's safe and will consistently work, and be able to explain this better to a colleague if it is.
Here is the relevant code for this situation:
<style type="text/css">
#background {
height: 150px;
}
</style>
......
......
<div id="background">
<div id="text_elem">
${text loaded from somewhere else}
</div>
</div>
......
......
<script>
(function() {
var text_elem = document.getElementById('text_elem');
var textElemHeight = text_elem.offsetHeight;
var newBkgdHeight = 96 + textElemHeight;
document.getElementById('background').style.height = newBkgdHeight + "px";
})();
</script>
Your IIFE will execute as soon as the <script> block containing it is loaded.
Since it's located at the end of the HTML, it will be executed after all the earlier HTML is loaded into the DOM.
The execution time is no different than if you hadn't put it in an IIFE at all, but just wrote it as top-level JavaScript code. The only difference from putting it in an IIFE is that the variables are local rather than global.

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

Replace text on webpage using javascript

I am trying to replace some text on my sites page using javascript. I must use javascript because the replacement is dependent on the site resolution. However I found that the code bellow doesn't work. Why is it? Does similar things work on iphone (these javascript functions)? Thanks.
<SCRIPT language="JavaScript">
<!--
if ((screen.width<=500))
{
document.body.innerHTML = document.body.innerHTML.replace('text to replace', 'replacement');
}
//-->
</SCRIPT>
The screen property does not have a resize cause it's like they built it in the factory :)
You're probably interested in window.innerWidth
probably you're also interested in listening for a resize event so here you go:
function doOnResize() {
var winW = window.innerWidth;
if(winW <= 500) {
document.body.innerHTML = document.body.innerHTML.replace('text to replace', 'replacement');
}
}
doOnResize(); // Do it as soon as you can
window.addEventListener("resize", doOnResize); // and on window resize
Also make sure to place the above <script> right before the closing </body> tag. This will make sure that the JS parser is in known about the DOM content before searching and replacing text.
Your code does not work because it is executed before the DOM is ready.
window.onload = function() { /* Your code here */ };
This will make sure the DOM is ready and everything is loaded.
What about using css and js (well, jquery would probably be best) to change the display attribute of the element on the event that triggers the text change?

Check if an element and its children have been loaded

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>

change two values with one if statement

I'm just starting to learn javascript, so this is likely a pretty simple question. I've tried searching for an answer, but I think I just don't know enough to be like, 'oh, this looks different but answers my question too.'
What I want to be able to do is to change the background color of a page based on the time of day, and also change an image based on the time of day. I have it working with an if...else if... statement for the background color placed in the head of the page, and a separate if...else if... statement affecting the image in the body.
The head script that changes the bg color looks like:
var d=new Date();
var time=d.getHours();
if (time>=0 && time<=5)
{
document.write ('<body style="background-color: 296688">')
}
else if
...and then the other times follow, each with a different color.
The body script that changes the image looks like:
<img src="" name="sunMoon" id="sunMoon" />
<script type="text/javascript">
var d=new Date();
var time=d.getHours();
var elem = document.getElementById('sunMoon')
if (time>=0 && time<=5)
{
elem.src = 'Images/sunMoon1.png'
}
else if
...and then the other times follow, each with a different src.
Is it possible to change the image AND the bg color using the same if...else if... statement in the head? I tried something like this in the head:
var d=new Date();
var time=d.getHours();
var elem=document.getElementById('sunMoon')
if (time>=0 && time<=5)
{
document.write ('<body style="background-color: 2966B8">');
elem.src="images/sunMoon1.png"
}
else if...
but it didn't work.
I think with the third (nonworking) example, either it's not possible to have a single if... do two things (change the bg color AND the image), or I'm just messing up the image code.
The problem with your third (non-working) bit of code is that you are trying to change the source attribute of an element that doesn't exist when the script is run. Generally speaking the browser parses the page's HTML from top to bottom, when it comes across a block it runs the code then continues on through the HTML. So in the example you have working the JavaScript code that alters the image source comes after the element in the HTML which is why it works. In the broken code you call elem=document.getElementById('sunMoon') in the head section, so no element with ID 'sunMoon' exists yet.
Generally it is best practice to place your scripts at the bottom of the page (just before the closing tag) so that they run after everything else has loaded, and don't block the rendering of the page. If you were to do that you'd need to change the code that alters the background colour as you can't write it directly to the body tag. The best practice solution would be to apply a different CSS class to the body depending on the time of day and then set up style rules for each class in your CSS.
So for example:
<script type="text/javascript">
var body = document.getElementsByTagName('body')[0];
var elem = document.getElementById('sunMoon');
if (time>=0 && time<5)
{
body.className = 'morning';
elem.src = 'Images/sunMoon1.png';
}
else if (time>=5 && time<10)
{
body.className = 'afternoon';
elem.src = 'Images/sunMoon2.png';
}
</script>
Then in your CSS you need rules for .morning, .afternoon etc
Yes you can, you can change the body style like this:
document.body.style.backgroundcolor = color;
Yes you can use
var d=new Date();
var time=d.getHours();
var elem=document.getElementById('sunMoon')
if (time>=0 && time<=5)
{
document.body.style.backgroundImage ="images/sunMoon1.png";
document.body.style.backgroundColor = "#2966B8";
}
use onload event
<html>
<head>
<script>
function onBodyload(e){
var image = document.getElementById('sunMoon');
if(condition){
document.body.style.backgroundcolor = ...
image.src = ...
}else if(condition){
document.body.style.backgroundcolor = ...
image.src = ...
}else if...
}
</script>
</head>
<body onload="onBodyload">
...
...
</body>
</html>

Categories

Resources