This thing is driving me mad... I have a simple js script wich checks for all the links tag () in a page and check if two of those links at least correspond to a given href attribute.
If I put the script in the main page as an inline script it works great. If I put it inside an external .js script on the same page, it doesn't find any element. Just like if it's only scanning its internal ones but not the parent document ones.
the script is this
var as,i,islink,l1,l2;
l1 = false
l2 = false
as=document.getElementsByTagName('a');
for(i=0;i<as.length;i++)
{
islink=as[i].href;
alert(islink);
if(islink == 'http://www.linktocheck.com/')
{
if(!as[i].getAttribute('rel')) {l1 = true;}
}
if(islink == 'http://www.linktocheck.com/somedir/somepage.asp')
{
if(!as[i].getAttribute('rel')) {l2 = true;}
}
}
if(!l1 || !l2) {alert('links not found in the page');}
I put alert(islink); for debug purposes to see if some link element has been found in the page or not.
The HTML of the calling page is this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title>page a</title>
<meta name="robots" content="noarchive" />
<meta content="text/html; charset=iso-8859-1" http-equiv="content-type" /></head>
<body>
<script src="externaljstochecklinks.js?PARAMETER=somevalue" id="uniqueid" type="text/javascript"></script><div style="margin-top: 6px;margin-bottom: 4px;text-align: center;">[...] <img src="http://www.linktocheck.com/skins/some/images/some.gif" alt="" style="border: none;vertical-align: middle;" /></div>
Why if I put the link check script inline it finds the elements if I put it as external it doesn't?
You have to wait for the DOM to finish loading before you can query it to find DOM elements.
Your script appears to be at the beginning of the <body> section which means it will execute BEFORE the DOM has been parsed and loaded. Thus, there is nothing yet loaded to find.
The simplest fix would be to move your <script> tag to the end of the body right before the </body> tag. You could also use an event listener and execute your code only when the event fires indicating that the DOM is ready.
Assuming the url to the external.js file is correct, the problem might be with the synchronous loading of the js files.
As soon as the js file is downloaded, it starts running. If this happens before the DOM finished loading, it can't find any <a> tag because they don't exist yet.
To test the hypothesis, include your external js file at the end of the <BODY> tag and see if it works.
To fix this issue permanently (and you don't want to include a JS file at the end of the body, you can defer the loading by either:
using an external library (such as jquery) and place the code inside $(document).ready()
placing your code inside window.onload event
trigger your own "ready" event
Related
I know this question was asked many times, but I haven't found answer. So why its recommended to include scripts at the end of body tag for better rendering?
From Udacity course https://www.udacity.com/course/ud884 - rendering starts after DOM and CSSOM are ready. JS is HTML parse blocking and any script starts after CSSOM is ready.
So if we got:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- content -->
<script src="script.js"></script>
</body>
</html>
CRP would be:
CSSOM ready > JS execute > DOM ready > Rendering
And if script is at head:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<!-- content -->
</body>
</html>
CRP would be the same:
CSSOM ready > JS execute > DOM ready > Rendering
This question is only about "sync" scripts (without async/defer attribute).
Scripts, historically, blocked additional resources from being downloaded more quickly. By placing them at the bottom, your style, content, and media could download more quickly giving the perception of improved performance.
Further reading: The async and defer attributes.
In my opinion, this is an outdated practice. More recently, the preference is for JavaScript to separate any code that requires the DOM to be present into a "DOMContentLoaded" event listener. This isn't necessarily all logic; lots of code can initialize without access to the complete DOM.
It's true that this causes a small moment when only the script file is being retrieved, and nothing else (for instance, images). This small window can be skipped by adding the async attribute, but even without it I recommend putting script tags in the head so that the browser knows as soon as possible to load them, rather than saving them (and any future JS-initiated requests) for last.
It is a best practice to put JavaScript tags just before the
closing tag rather than in the section of your HTML.
The reason for this is that HTML loads from top to bottom. The head
loads first, then the body, and then everything inside the body. If we
put our JavaScript links in the head section, the entire JavaScript
file will load before loading any of the HTML, which could cause a few
problems.
1.If you have code in your JavaScript that alters HTML as soon as the
JavaScript file loads, there won't actually be any HTML elements
available for it to affect yet, so it will seem as though the
JavaScript code isn't working, and you may get errors.
2.If you have a lot of JavaScript, it can visibly slow the loading of your page
because it loads all of the JavaScript before it loads any of the
HTML. When you place your JavaScript links at the bottom of your HTML
body, it gives the HTML time to load before any of the JavaScript
loads, which can prevent errors, and speed up website response time.
One more thing: While it is best to include your Javascript at the end
of your HTML , putting your Javascript in the of your
HTML doesn't ALWAYS cause errors. When using jQuery, it is common to
put all of your code inside a "document ready" function:
$("document").ready(function(){ // your code here });
This function basically says, don't run any of the code inside until
the document is ready, or fully loaded. This will prevent any errors,
but it can still slow down the loading time of your HTML, which is why
it is still best to include the script after all of the HTML.
Images placed below the script tag will wait to load until the JS script loads. By placing the script tag at the bottom you load images first, giving the appearance of a faster page load.
I think it depends on your website or app. Some web apps are based on JavaScript. Then it does not make sense to include it at the bottom of the page, but load it immediately. If JavaScript just adds some not so important features to some content based page, then better load it at the end. Loading time will almost be the same, but the user will see the important parts earlier (before the page finished loading).
It’s not about a whole site loading faster, but giving a user the impression of some website loading faster.
For example:
This is why Ajax based websites can give a much faster impression. The interface is always the same. Just some content parts will alter.
This was an extremely useful link. For any given webpage, a document object model is created from the .html. A CSS object model is also created from .css.
We also know that JS files also modify objects. When the browser encounters a tag, the creation of DOM and CSS object models are immediately halted when the script is run because it can edit everything. As a result, if the js file needed to extract information from either of the trees (DOM and CSS object model), it would not have enough information.
Therefore, script srces are generally at the end of the body where most of the trees have already been rendered.
Not sure if this helps,
But from this resource script-tag-in-web the inline script is always render blocking even if kept at the end of body tag.
Below inline script is first render blocking.Browser will not paint anything on screen till the long for loop is executed
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script>
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
But'index.js' below is not initial render blocking, the screen will be painted , then once external 'index.js' is finished running the span tag will be updated.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script type="text/javascript" src="./index.js">
</script>
</body>
</html>
index.js
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
I have a weird issue that i am hoping someone can help resolve.
Problem
When i load html dynamically via .load() function, if any aspect of html in the loaded fragment tries to access the javascript query functions in original HTML page, it doesn't work. Example code below:
Main HTML page (main.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<!--javascript load functions etc... standard header stuff -->
</head>
<body>
<div id="dynamic_section_fragment"></div>
Load Fragment
<script type="text/javascript">
// <![CDATA[
function loadFragment() {
$("#dynamic_section_fragment").load("/api/fragment/");
};
$(".checkvalue").click(function () {
$.getJSON("/api/checkvalue", {term: $(this).attr('value')}, function () {
console.info("submitted for checking");
})
});
// ]]>
</script>
</body>
</html>
FRAGMENT File (fragment.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
</head>
<body>
<div th:fragment="check_value">
<br/>
Check the value in the attribute field
<br/>
<a href="javascript:" th:attr="value='123'" class="checkvalue">Check This<a/>
</div>
</body>
</html>
SPRING MVC Controller Method
#RequestMapping("/api/checkvalue")
public String getFragment(Model model) {
return "fragment :: check_value";
}
So a run down of actions:
-Main.html page loads
-User clicks on Load Fragment hyperlink
-Javascript dynamically loads the relevant fragment into the div
-User clicks on Check This hyperlink, nothing happens
Is there something i am missing or something i need to be aware?
It is as if Thymeleaf has preregistered all the possible scenarios of events and doesn't allow any others.
Only way i have been able to get it to work is by injecting the "checkvalue" javascript within the fragment, which as you can agree is a bad way of doing things.
Help is appreciated.
You are applying the click event listener to all existing objects with the checkvalue class.
$(".checkvalue").click(function ()
What you rather wish to do (to make the click event apply to all the existing and any new added, dynamically) is to set a event on a parent in the dom tree (parent both to the existing and to all that will be added).
In your case, the body tag would probably be the safe bet.
The following should suffice:
$('body').on('click', '.checkvalue', function() { ...
Simplified, the code will apply a listener on the body element instead of the .checkvalue objects, and whenever a object with the .checkvalue class is clicked (wether dynamically or statically loaded), the event will fire.
edit
I would also suggest that you, in your javascript, don't use jquery before you know for certain that it is loaded.
The jquery lib have a way of fixing this for you, by using the $( document ).ready() function:
$( document ).ready(function() {
// All jquery dependant code here.
});
I want to display another html page on my html page, that html page is generated. So I don't have it's src, only the content. It has doctype, head, body, all stuff. So I decided to use iframe. The problem is that I can't assign the whole text to a variable, as I get errors, that there is an unsupported character, like "<" etc. How to deal with it?
I'm trying to do something like this:
window.onload = function() {
var iframeDocument = document.getElementById("myIframe").contentDocument;
var ss = "
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
</head>
<body>
</body>
</html>";
iframeDocument.write(ss);
iframeDocument.close();
}
So my problem is how to escape that text so it won't cause browser errors?
Also html content is generated dynamically, so in my code there is no that text, there is struts action variable. But after my code gots executed in browser, that's what I see in there.
The easiest way to solve this is to create a new aspx page, that creates that html you need in your iframe and set the src of the iframe to that aspx page (or php, depends on what you are using).
So lets say you create a new aspx page called Frame.aspx. You then add <iframe src="Frame.aspx?SomeParameter=SomeValue" /> to your parent window.
This is a much nicer approach and much more maintainable. Also it prevents having the iFrame contents twice (once in your javascript variable and once as content of the iframe).
I am messing around with JavaScript experimenting to get a feel for it and have already hit a problem. Here is my html code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<script type="text/javascript" src="testing.js"></script>
</head>
<body onload="writeLine()">
</body>
</html>
Here is the JavaScript testing.js:
function writeLine()
{
document.write("Hello World!")
}
Here is the style sheet styles.css:
html, body {
background-color: red;
}
So a very simple example, but I may have chose an awkward example, using on-load in a body tag. So the code above loads and runs the function, but the style sheet does nothing, unless I remove the script tags in the head. I have tried putting the script tags everywhere else, but nothing works. I have researched on-line how to properly link to JavaScript files, and have no found no clear solution, can anyone point out my error?
I have used JavaScript before, but I want a clear understanding from the beginning before I use it any longer
You cannot use document.write after the document is closed (which it will be when onload fires) without destroying the existing document (including links to stylesheets).
Instead, use DOM manipulation, which is covered by chapters 8 and 9 of the W3C JavaScript Core Skills.
Your problem is with the document.write() called in a wrong moment*. This method prints given text at current place in the page as was intended to work while the page still loads. Because you are calling it when the whole page was loaded, the results are unexpected (undefined?)
Instead you should manipulate the dom tree directly:
function writeLine() {
var text = document.createTextNode("Hello World!");
document.body.appendChild(text);
}
Actually in Opera browser I see red background for few milliseconds and then it goes back to white. Try commenting out document.write() - the background is as expected. Moreover you should include <script> tag at the end of body, but this won't solve your problem.
* to be honest, there is no good moment for calling document.write(), avoid it
In your particular example it doesn't matter where the script tag is added as the document.write command executes after the content is rendered, overwriting the existing content.
If you add an alert before overwriting the content you can see your page is red before it gets overwritten with Hello World.
I'm not sure what I'm doing wrong here:
index.html
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "XHTML1-s.dtd" >
<html xmlns="http://www.w3.org/TR/1999/REC-html-in-xml" xml:lang="en" lang="en" >
<head>
<script type="text/javascript" src="scripts/eventInit.js"></script>
</head>
<body>
<p id="javascriptWarning">This page will not work with JavaScript disabled.</p>
</body>
</html>
eventInit.js
window.onload = function () {
alert("check"); // works
var jsWarning = document.getElementById("javascriptWarning");
jsWarning.onclick = function () {
alert("hi"); // works
};
jsWarning.onload = function () {
alert("loaded"); // fails
};
}
And yet, nothing happens. What am I doing wrong? I've tried other events, like onmouseover and onload.
I'm doing this in Visual Studio, and intellisense isn't giving me options for setting any event handlers. Is that because I'm doing this wrong?
I have confirmed that JS is working on my setup; just putting alert("hi") in a script and including it does work.
It might be important to note that I'm doing this in JScript, since I'm using Visual Studio 2010, so perhaps event handling is different?
Updated to remove '-' from the ID name, but it still doesn't work.
Updated added the window.onload block. Now onclick works, but onload doesn't.
You are trying to set a load event on a paragraph. Only objects which load external data (window, frame, iframe, img, script, etc) have a load event.
Some JS libraries implement an available event (such as YUI) — but you know the paragraph is available, since you're setting an event on it, and you couldn't do that if it was unavailable.
maybe you forgot to have the code block inside a
window.onload = function() {
// btn click code here
}
You have to wait for the document to be parsed before you can go looking for elements by "id" value. Put your event handling setup into an "onload" function on the window object.
The browser won't fire an "onload" event on your <p> tag. You won't need that anyway if you do your work in the "onload" handler for the window as a whole.
[soapbox] Use a framework.
The script is executed before the desired element exists. Additionally, I don't think, p has an onload-Event. Windows, frames and images, yes, but paragraphs?
You should use <body onload="init();"> or window.onload=function(){ … } or a library function, if you use a library. Example:
index.html
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "XHTML1-s.dtd" >
<html xmlns="http://www.w3.org/TR/1999/REC-html-in-xml" xml:lang="en" lang="en" >
<head>
<script type="text/javascript" src="scripts/eventInit.js"></script>
</head>
<body>
<p id="javascriptWarning">This page will not work with JavaScript disabled.</p>
</body>
</html>
scripts/eventInit.js
window.onload=function(){
alert('JS is working!');}
Edit: Okay, I am very sure, p makes no use of an onload event handler. And it's no wonder, you don't need it. If you want to execute JS code just after the paragraph is finished, do this:
<p>
<!-- stuff -->
</p>
<script type="text/javascript">
/* stuff */
</script>
Instead of this:
jsWarning.onload = function () {
alert("loaded"); // fails
};
try this
if(jsWarning) alert("loaded");
I think someone above mentioned checking for the existence of the element. At this stage the element should be present but it does no harms to check for it.
I think you have to make sure your JavaScript is binding.
Is your javascript before or after your paragraph element, for some reason my brain is aiming towards that.
I would look into using something like jQuery, it will help.
using jQuery your code would be (with the relevant jQuery files included of course):
$(document).ready(function()
{
$("#javascript-warning").click(function(){
alert("HELLO");
});
});
I don't think hyphens are valid in class names when used in conjunction with JavaScript. Try an underscore instead.
onload is a window event.