document.getElementById('blocks').value = blocks; is giving an error - javascript

Okay so, I once tried this a long time ago and it never happened before.
if I do
var blocks = 0;
document.getElementById('blocks').value = blocks;
Uncaught TypeError: Cannot set property 'value' of null
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" href="/css/Index.css">
<script src="/js/Index.js"></script>
</head>
<body>
<input type = "text" id="blocks"/>
</body>
</html>

Try moving your script to the bottom of the body. Element does not exist at the time of execution.
<head>
<title>Home</title>
<link rel="stylesheet" href="/css/Index.css">
</head>
<body>
<input type = "text" id="blocks"/>
<script src="/js/Index.js"></script><!-- here-->
</body>

If your script is saved in its own JS file (i.e. not as a <script> tag in the HTML), you cannot access DOM elements until the document is loaded. So, wrap your code in an onload event handler:
document.onload = function() {
var blocks = 0;
document.getElementById('blocks').value = blocks;
}

Try placing the <script> tag at the end of your <body> element to ensure that the element is accessible at the time the script is called:
<!DOCTYPE html>
<head>
<title>Home</title>
<link rel="stylesheet" href="/css/Index.css">
</head>
<body>
<input type = "text" id="blocks"/>
<script src="/js/Index.js"></script>
</body>

load your script in footer section or very end of the body instead of head. Your script is executing before DOM is loaded or call the specified statements under load event.

This is failing because your script is running before the DOM is finished rendering. You should always place your DOM-manipulating script inside document.onload function, which runs after the DOM has finished loading.
Also, you should always check for NPE (NullPointerException); it's a good habit to get into:
document.onload = () => {
const element = document.getElementById('blocks');
if (element) {
element.value = 0;
} else {
// consider publishing some warning
console.error("Could not find element #blocks");
}
}

As others have suggested, the common practice to ensure your script runs after elements have loaded is to move the script tag to the bottom of the body, after the elements themselves. However, a more modern approach is to use the defer attribute on your script tag: this ensures the script won't load until your DOM has loaded, but you don't need to worry about the tag's placement in the page relative to DOM elements you'll be manipulating. It's supported by all modern browsers, even IE10+.
So simply add defer onto your existing <script> tag and everything should work :)

Related

Is it possible to use javascript to modify a script element?

Is there a way to use javascript to modify a script element?
Like for example:
HTML:
<script id="something" src="/js/file.js"></script>
Javascript:
var something = document.getElementById("something");
something.src = "/js/anotherfile.js"
Is it possible? Because I have a bit of code that works like that and it sort of doesn't work
To be specific, here's the code:
<!DOCTYPE html>
<html>
<head>
<title>MyohTheGod's Website</title>
<link rel="icon" type="image/x-icon" href="/supercorn.gif" defer>
</link>
<link id="css" href="/css/dark.css" rel="stylesheet" type="text/css">
</link>
<script src="/js/particles.js" defer></script>
<script src="/js/header.js"></script>
<script src="/js/theme.js"></script>
<script>window.alert("Welcome to the Home of MyohTheGod. You can play games, check out our web proxies, and more. Also, please do check out the About page. Press OK to continue...");</script>
</head>
<body>
-snip-
</body>
<script id="foot" src="/js/footer.js"></script>
</html>
<script>
-snip-
</script>
var css = document.getElementById("css");
var foot = document.getElementById("foot");
function toggleDLmode(m) {
-snip-
if (dlmodebool) {
css.href = "/css/dark.css"
foot.src="/js/dark-footer.js"
} else {
css.href = "/css/index.css"
foot.src="/js/footer.js"
}
}
-snip-
It is working, do you inspect it? It does changed, but maybe you're thinking, "hm why this /js/anotherfile.js is not downloaded?". Well because of the script tag is already rendered and already downloaded, so you can't do that. What you can do though add NEW script tag.
Maybe this will help How to dynamically change the script src?. This links would explain more why your code "does not work".
There certainly is. You can use document.scripts which returns an collection that you can iterate through like an array. You can change the code using the innerHTML property very much like a normal element. See here https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
Edited to add: If you've got a html page with multiple script tags, the document.script collection has each script in the order they appear. The code below will log out the source (src tag) or the actual javascript for each script element.
You can also 'write' javascript by setting the innerHTML property.
IMHO it's a bit of a solution that's looking for a problem but at least it gives you access to the number of scripts you have.
[...document.scripts].forEach(script => {
if (script.src != '') {
console.log("Script source:" + script.src);
} else {
console.log(script.innerHTML);
}
});

How do I make the querySelector look in a specific included document only?

On my index page I have a number of includes.
<section><?php include('content/content1.php') ?></section>
<section><?php include('content/content2.php') ?></section>
<section><?php include('content/content3.php') ?></section>
In each of them I have a unique script (and some other things which is not shown here).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Content1</title>
<link rel="stylesheet" href="content/sketch.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"></script>
</head>
<body>
<div class="frame">
<canvas></canvas>
</div>
<script src="content/content1.js"></script>
</body>
The <canvas> tag is what the querySelector in the javascript calls to.
var canvas = document.querySelector('canvas');
This works, but only for the first content file. It seems the querySelector looks at the whole loaded page, instead of just inside the body of the document where the script is placed. Google console says: "Indentifier 'canvas' has already been declared".
I have tried setting an id on the canvas-element:
<canvas id="canvas1"></canvas>
var canvas = document.querySelector('#canvas1');
But it's not working. How do I get around this?
You can use document.currentScript to get the tag of the currently running script tag. From there, you can navigate to its containing section, and from there, get to the canvas descendant.
You should also put everything into an IIFE to avoid global variable collisions.
(() => {
const canvas = document.currentScript.closest('section').querySelector('canvas');
// ...
})();

How to render html from a external js file

This might be a dumb question but I have actually never done this and what I am trying is not working.
I have 2 files
test.html
test.js
I am linking the js as an external in test.html
<!doctype html>
<html>
<head>
<script type="text/javascript" src="test.js"></script>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body>
</body>
</html>
In my js file I have something like this
document.appendChild('<div>testing</div>')
I also tried
document.getElementsByTagName('body').appendChild('<div>testing</div>')
What I am doing wrong? I just want to learn how to generate html from an external js file for a future project I am working on.
You should generally try to run scripts that depend on the page after the document has been parsed, not before - if you put the script in <head> and run it immediately, the <body> has not been created yet. Give your script tag the defer attribute so that it only runs after the document is fully parsed:
<script defer type="text/javascript" src="test.js"></script>
appendChild accepts an element as a parameter, not a string
You need to append to the body, not the document itself (Only one element on document allowed.)
If you want to append an HTML string, assign/concatenate to the .innerHTML property
Assigning to .innerHTML will corrupt existing references to elements inside, including listeners. In order to keep listeners active, use insertAdjacentHTML instead:
document.body.appendChild(document.createElement('div'))
.textContent = 'testing1';
// Another method:
document.body.innerHTML += '<div>testing2</div>';
// Another method:
document.body.insertAdjacentHTML('beforeend', '<div>testing3</div>');

Why scripts at the end of body tag

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);

JavaScript not working as an external file

I'm new to HTML, JavaScipt and everything related to programming, and I'm trying to create a simple page.
Now, I'm stuck with the following problem: I want to change the date of my main.html file, but the main.js is not working. I've already change the <script> position to inside the <body>, after the </span> and even after the </body>, without success. If the content of the main.js is within the HTML it works fine, but as a external file it doesn't.
Here is my main.html:
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="main.js"></script>
<title>Page 1</title>
</head>
<body>
<p>WRF<br>
<span id="data">18/09/1987</span></p>
</body>
</html>
My main.js is just:
document.getElementById("data").innerHTML = "JUBA";
I've looked through the internet and through this forum, but all answers that I've found did not worked.
The files are on the same directory and the main.css works fine.
Thank you in advance.
At time you call main.js element #data was not created in DOM tree. You can fix this by putting the link to your Javascript file right before closing the body like this:
<script type="text/javascript" src="main.js"></script>
</body>
Document Object Model (DOM) is not "READY".
Try use onload event, inside main.js:
window.onload = function() {
document.getElementById("data").innerHTML = "JUBA";
};
If needs more "fast" than onload, use jquery with $(document).ready:
html:
<link href="main.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="main.js"></script>
main.js:
$(document).ready(function() {
$("#data").html("JUBA");
});
window.onload vs $(document).ready()
Answer by #Guffa:
The ready event occurs after the HTML document has been loaded, while the onload event occurs later, when all content (e.g. images) also has been loaded.
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.
The element is not yet accessible when you run the script.
Either you can put the script at the end of the page or delay the execution.
You could put the JavaScript in the <body> tag after the rest of the page. When the browser loads it, the <span> will already be there to be edited.
As per your code the script will be called first then page will be loaded, therefore when the script is running there will not be any element having id data because yet page have to be loaded. There are many ways to achieve what you need.
1. Add a script tag before or after end of body like
or
<script type="text/javascript" src="main.js"></script>
</body>
Write .js file above before body i.e. in head tag and write the whole javascript code in onload method.
window.onload=function(){
document.getElementById("data").innerHTML = "JUBA";
};
window.onload=function(){
document.getElementById("data").innerHTML = "JUBA";
};
<p>WRF<br>
<span id="data">18/09/1987</span></p>

Categories