While True loop prevents page from loading - javascript

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>

Related

Changing global css with js

I have a background image that is in a style tag at the top of my html. And I want to change it when it turns to night time where the user is. So during the day it is imageA and during night time it is imageB.
The reason the css is in the header is because of my file layout and it wouldn't be able to access the image otherwise.
How do I change this global css styling from an external js file? I want to change the background image value. Any help would be great thank you.
let d;
d = new Date();
var now = d.toString().slice(16,18);
console.log(now);
if (now <= 5, now >= 20) {
console.log("it is night time")
//the code to change the image would be here
} else {
console.log("it is daytime")
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seldom Seen</title>
<link rel="stylesheet" href="css/flip.css" />
<!--the lines below here is the part i want to change-->
<style>
.bg-image{
background-image:url("images/imageA.png");
}
</style>
</head>
Not sure if this is what you are asking for, but you can use this snippet to change the background-image through JavaScript:
document.querySelector(".bg-image").style.backgroundImage = "url(images/imageB)";
I'm not aware of any ways to modify CSS in the header using JavaScript, but here are two approaches that would solve your problem:
Assign one of the background images to an additional class, which overrides the original assignment by CSS specificity.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seldom Seen</title>
<link rel="stylesheet" href="css/flip.css" />
<!--the lines below here is the part i want to change-->
<style>
.bg-image{
background-image:url("images/imageDay.png");
}
.bg-image.night{
background-image:url("images/imageNight.png");
}
</style>
</head>
const bg = document.querySelector('.bg-image');
let d;
d = new Date();
var now = d.toString().slice(16,18);
console.log(now);
if (now <= 5, now >= 20) {
console.log("it is night time");
bg.classList.add('night');
} else {
console.log("it is daytime");
bg.classList.remove('night');
}
Modify the style attribute of the element inline:
if (now <= 5, now >= 20) {
document.querySelector('.bg-image').style.backgroundImage = url('./images/imageNight.jpg');
}
else {
document.querySelector('.bg-image').style.backgroundImage = url('./images/imageDay.jpg');
}

How to track clicks of a button?

I’m trying to track the clicks on a button on my website. I’ve tried adding the following but to no success. I’m a noob to JS..
function trackButton(e) {
onPage.innerHTML = ++i;
}
var i = 0;
var onPage = document.getElementById(‘track’);
var clickCount = document.getElementById(‘bttn’);
clickCount.addEventListener('click', function (e) {
addOne(e);
}, false);
You did some mistake:
The function addOne doesn't exist, it's trackbutton
it's i++ to increment a value, not ++i
And some tips for you:
Use let and const (ES6) for the variable, not var
And the e for the event is useless here, you are not using it, so it's not mandatory here
Do these change and it must work !
UPDATE:
To increment a value ++i works, see the documentation
Change the quotes ‘‘ with " " or ' '.
Like so: document.getElementById(‘track‘) to document.getElementById('track')
I was checkin your code and its almost all right, i think that the problem its in your addOne function, here is a way to resolve the problem.
i creat the button and paragraph elements in html and in javascript a variable n where we are going to storage the clicks tha the user did and we increment n when the function its called in the button's event
var n = 0;
var button = document.getElementById('track');
button.addEventListener('click', trakeo);
var texto = document.getElementById('number');
function trakeo(){
n++
texto.innerHTML = n;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A Great Demo on CodePen</title>
</head>
<body>
<button id="track">Button</button>
<p id="number"></p>
</body>
</html>
Try to use
addEventListener('click',)
https://www.w3schools.com/jsref/met_element_addeventlistener.asp

Why won't my images change when clicked even though the logic seems pretty straight forward?

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.

object.innerHTML not updating properly?

I tried to make a progress bar in javascript, but it didnt load till my
program was finished. How can i make it updating while the program is still running?
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="main" onclick="my()">1</div>
<button onclick="myFunction()">start</button>
<script>
function myFunction() {
for(var i=0;i<1000000;i++){
document.getElementById("main").innerHTML=i;
}
}
</script>
</body>
</html>
Use setInterval method which runs in the background without blocking. Once reached the condition you can clear the interval using clearInterval method.
function myFunction() {
// get element reference and cache in a variable
let main = document.getElementById("main"),
// initialize i as 0
i = 0;
// keep interval reference for clearing once i reached 1000000
let intrvl = setInterval(() => {
// check value of i and increment, if reached 1000000 clear the interval
if (i++ === 1000000) clearInterval(intrvl);
// update the content of main element
main.innerHTML = i;
}, 1000); // set required delay in millisecond, any value lesser than 10 will be automatically converts to 10
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="main" onclick="my()">1</div>
<button onclick="myFunction()">start</button>
<script>
function myFunction() {
let main = document.getElementById("main"),
i = 0;
let intrvl = setInterval(() => {
if (i++ === 1000000) clearInterval(intrvl);
main.innerHTML = i;
},1000);
}
</script>
</body>
</html>
I used setInterval instead of for cicle and i used parseInt() to get integer value of your div innerHTML and then increment it
setInterval(myFunction, 1000) runs myFunction() every 1000 milliseconds
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="main" onclick="my()">1</div>
<button onclick="setInterval(myFunction, 1000)">start</button>
<script>
function myFunction(){
var value = parseInt(document.getElementById("main").innerHTML);
document.getElementById("main").innerHTML=value+1;
}
</script>
</body>
</html>

Show changes from an currently executing for loop

I could need some help, or maybe just an answer. Is there a way to show changes made by aa js within an executing for loop ? I know there is a way with setInterval, but I have an example with a greater progress where I need it to progress the problem with a for loop. So here is my try:
<!doctype html>
<html>
<head>
<title>life change test</title>
<meta charset="UTF-8">
</head>
<body>
<div id="wrapper">
</div>
<script type="text/javascript">
var el = document.getElementById("wrapper");
/*var i = 0;
var counter = setInterval(function(){
el.innerHTML = i;
i++;
if(i == 18000){
clearInterval(counter);
}
}, 10);*/
for (var i = 400000; i >= 0; i--) {
el.innerHTML = i;
};
</script>
</body>
</html>
My Firefox just freezes until it is completely done, and than displays the result. Is there a chance to actually see the progress ?

Categories