I apologise if my question seems simple, I am still trying to figure out JavaScript. I am building a website where I want the contents of a <p> to constantly change. I want it to loop over the contents of an array defined in my javascript code. However, when I put everything in a while (true) (because I want it to happen constantly), the <p> content never changes and the page is stuck on loading.
Here is the code I have so far:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
function changeDynamicText() {
var descriptions = ['list', 'of', 'strings', 'to', 'loop', 'over'];
let i = 0;
while (true) {
window.setTimeout(function() {
document.getElementById("dynamicline").innerHTML = descriptions[i];
}, 600);
i = i + 1;
if (i >= descriptions.length) i = 0;
}
}
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
Help of any kind is greatly appreciated.
When you use while(true), it will block the JavaScript event loop and therefore no longer render the rest of the body.
You can achieve what you're trying to do by working asynchronously. You already did use setTimeout in there, but you could also use setInterval to trigger the method on a recurring basis.
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
setInterval(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = i + 1;
if (i >= descriptions.length) i = 0;
}, 600);
}
You can use setInterval instead.
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
setInterval(() => {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = (i + 1) % descriptions.length;
}, 600)
}
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
You can easily do this with setInterval instead of setTimeout. Use setInterval when you need something to constantly do something in periods of time.
And I moved the i manipulation inside of the interval because you want that to execute each time the function gets called.
Also, it's just a really good habit to get into to put your script tags as the very last element of the body in the HTML document. This way you can ensure that all DOM content has loaded before attempting to manipulate the DOM.
Here is a JSFiddle with the code below: https://jsfiddle.net/mparson8/41hpLaqw/2/
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
<script>
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
let interval = window.setInterval(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = i + 1;
if (i >= descriptions.length) i = 0;
}, 600);
}
changeDynamicText();
</script>
</body>
</html>
while (true) always blocks the page until it finishes using a break statement, in your code is never finishing, so what you need to do is call the function itself in the timeout (and make i a global variable to keep track of the array position)
let i = 0;
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
setTimeout(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
changeDynamicText()
}, 600);
i = i + 1;
if (i >= descriptions.length) i = 0;
}
loops are blockers infinite loops are infinite blockers. What you need is a time based switcher - a built in timeout functionality which you can call in a cyclical manner - or a, on interval ticker. Any of them will do...
function changeDynamicText() {
var descriptions =
['list','of','strings','to','loop','over'];
var i = 0;
setInterval( tick, 800 );
function tick( ) {
dynamicline.innerHTML = descriptions[ i++ ];
if(i >= descriptions.length-1 ) i = 0
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
I'm trying to display a new image upon clicking on the current image. The problem's that upon clicking on img-1, it some how skips to img-3. However, if I remove the the second if(), it correctly goes to the next image (img-2).
How's this happening and how can I fix it?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="index.css">
<title>Title</title>
</head>
<body>
<img id="the-image" onclick="clickedImage()" src="https://www.folkdeal.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/f/d/fd-ea10150-1.jpg" alt="image down"/>
<script type="text/javascript">
let theImage = document.getElementById('the-image');
let index = {
"img-1" : "https://www.folkdeal.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/f/d/fd-ea10150-1.jpg",
"img-2" : "http://image.en.yibada.com/data/images/full/66771/the-legend-of-zelda-japanese-hepburn-zeruda-no-densetsu-is-a-high-fantasy-action-adventure-video-game-series-created-by-japanese-game-designers-shigeru-miyamoto-and-takashi-tezuka.png",
"img-3" : "https://www.geekisus.com/wp-content/uploads/2018/08/01_1575-11-400x400.jpg"
};
let clickedImage = () => {
if(theImage.src === index["img-1"]) {
theImage.src = index["img-2"];
}
if(theImage.src === index["img-2"]) {
theImage.src = index["img-3"];
}
}
</script>
</body>
</html>
When you do
theImage.src = index["img-2"]
this will be true
if(theImage.src === index["img-2"])
and then
theImage.src = index["img-3"];
will be executed, effectively skipping the second image. You probably want to change the second if into an else if.
This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 5 years ago.
Would anyone know why I’m able to get my code to run on codepen, but not on my desktop? I keep getting a “can't read appendChild” error when I run my code on my desktop. I am new to coding and just started teaching my self how to manipulate the DOM.
https://codepen.io/unicorn1/pen/JpYqjJ
const container = document.querySelector('#container');
const content = document.createElement('div');
content.classList.add('content');
content.textContent = 'Dom text-content!';
container.appendChild(content);
Error Message
the script should be put at the bottom before the body ends
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>
THE TITLE OF YOUR WEBPAGE
</h1>
<div id="container"></div>
<script>
const container = document.querySelector('#container');
const content = document.createElement('div');
content.classList.add('content');
content.textContent = 'Dom text-content!';
container.appendChild(content);
</script>
</body>
</html>
or you can put the content of script in the window.onload callback like this:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
window.onload = function() {
const container = document.querySelector('#container');
const content = document.createElement('div');
content.classList.add('content');
content.textContent = 'Dom text-content!';
container.appendChild(content);
};
</script>
<h1>
THE TITLE OF YOUR WEBPAGE
</h1>
<div id="container"></div>
</body>
</html>
the principle is that,you can manipulate DOM after the DOM have loaded;you can't manipulate DOM before loaded.that is how window.onload and script position works;
also ,you can change the window.onload to DOMContentLoaded
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
document.addEventListener('DOMContentLoaded', function() {
const container = document.querySelector('#container');
const content = document.createElement('div');
content.classList.add('content');
content.textContent = 'Dom text-content!';
container.appendChild(content);
}, false);
</script>
<h1>
THE TITLE OF YOUR WEBPAGE
</h1>
<div id="container"></div>
</body>
</html>
Why iframe alert undefined if use setTimeout for changing iframe.src attribute?
Change iframe.src attribute outside of setimeout work.
How to modify|intercept iframe's eval, Function, Element.prototype.appendChild objects if they are different from parent's window (Element !== parent.Element) ?
main.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>IFrame var pass test</title>
</head>
<body>
<script type='text/javascript'>
ifel = document.createElement('iframe') ;
ifel.frameBorder = ifel.style.width = ifel.style.height = 0 ;
ifel.style.position = 'absolute' ;
ifel.id = 'id-iframe-x' ;
document.body.appendChild(ifel) ;
ifel.contentWindow.Z = 'Y' ; // window changed after load ???
ifel.addEventListener('load', function () {
ifel.contentWindow['Z'] = 'Z' ; // change after load
}) ;
// ifel.src = 'iframe.html' ; // <-- WORK !
setTimeout(function() { // <-- NOT WORK !
ifel.src = 'iframe.html' ;
}, 3000) ;
</script>
</body>
</html>
iframe.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>IFrame var pass test</title>
</head>
<body>
<script type='text/javascript'>
alert(typeof window.Z) ;
</script>
</body>
You're changing the value of iframewindow.Z from the parent after the iframe is loaded -- this is correct. Your iframe, however, runs its alert before the iframe is finished loading. You need to define a function on the iframe window and call it from the parent window after the iframe is loaded. You could also try to defer the iframe script, but that'll create a race condition -- it might work now, but maybe not always, especially if you have asynchronous data added from the parent.
I have a JavaScript statement on the bottom of my page that I want to trigger ONLY if a certain HTML comment is available
<!-- mytriggercomment -->
In the above example, if the mytriggercomment is detected within the current page, only then should the JavaScript statement trigger. What is the preferred way of doing this?
May not work for older browsers, but this way is a logical DOM approach:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
window.onload = function () {
var treeWalker = document.createTreeWalker(
document,
NodeFilter.SHOW_COMMENT,
{acceptNode: function(node) {
if (node.nodeValue.trim() === 'mytriggercomment') {
return NodeFilter.FILTER_ACCEPT;
}
}}
);
var nodeList = [];
while(treeWalker.nextNode()) nodeList.push(treeWalker.currentNode);
alert(nodeList)
};
</script></head>
<body>
</body>
</html>
<!-- mytriggercomment -->
If you know it will always be at the bottom, you may be able to target it like:
window.onload = function () {
alert(document.documentElement.nextSibling &&
document.documentElement.nextSibling.nodeValue.trim() === 'mytriggercomment')
};