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 ?
Related
The unexpected behavior I'm getting is when clicking the donate or undonate button. It takes 2 clicks initially for the tracker to display the incremented or decremented number despite the color change happening immediately. Once it does change the number on the second click, the 3rd click and on using the same button will work normally to increment or decrement.
In addition to that, if you switch the button you're clicking to the other, it still performs the previous action first.Hopefully this explanation of the issue makes sense. Appreciate any direction that can be given as I am still new!
HTML:
<!DOCTYPE html>
<head>
<link rel="stylesheet" href='style.css' />
<title>Front-End Portfolio Project</title>
</head>
<body>
<h1>Donate Food 2 Me</h1>
<p id="container"></p>
<p id='caption'>food quantity</p>
<button id="donate">Donate</button>
<button id="undonate">Un-Donate</button>
<script type="text/javascript" src='main.js'></script>
</body>
</html>
JS:
const donateButton = document.getElementById("donate");
const unDonateButton = document.getElementById("undonate");
const tracker = document.getElementById("container");
var i = 0;
tracker.innerHTML = i;
donate = function(){
donateButton.style.backgroundColor = 'red';
tracker.innerHTML = i++;
}
undonate = function(){
unDonateButton.style.backgroundColor = 'blue';
tracker.innerHTML = i--;
}
donateButton.addEventListener("click", donate);
unDonateButton.addEventListener("click", undonate);
The only mistake you made is ignoring the difference between i++ and ++i (i-- and --i).
Change your code as below (You can see the result here):
donate = function(){
donateButton.style.backgroundColor = 'red';
tracker.innerHTML = ++i;
}
undonate = function(){
if (i > 0) {
unDonateButton.style.backgroundColor = 'blue';
tracker.innerHTML = --i;
}
}
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 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>
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
I am learning Javascript language and so I am on a project while I came across this issue. Here is the code:
function koko() {
items = document.getElementsByTagName("a");
for (var pos = 0; pos < items.length; pos++) {
this.items[pos].addEventListener("click", function() {
console.log(pos);
});
}
}
koko();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Click me 1
Click me 2
Click me 3
</body>
</html>
Every time I click on any item with a tag I get same value on the console that is items.length. But I am expecting it to print the position/index of the element that is clicked. For example, if I click Click me 2 it should print 1. What am I missing here?
When the click listener is executed, pos has the value of 3, your code is fine, look at this example:
function koko() {
items = document.getElementsByTagName("a");
for (var pos = 0; pos < items.length; pos++) {
this.items[pos].addEventListener("click", function() {
console.log(this.innerHTML);
});
}
}
koko();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Click me 1
Click me 2
Click me 3
</body>
</html>
Try this for the desired results
function koko() {
items = document.getElementsByTagName("a");
for (var pos = 0; pos < items.length; pos++) {
this.items[pos].id = pos;
this.items[pos].addEventListener("click", function() {
console.log(this.id);
});
}
}
koko();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Click me 1
Click me 2
Click me 3
</body>
</html>
You function logs pos, WHEN the button is clicked, not when the event listener is added. To fix this, you can use this code:
function koko() {
items = document.getElementsByTagName("a");
for (var pos = 0; pos < items.length; pos++) {
this.items[pos].addEventListener("click", function() {console.log(this.id);});
}
}
koko();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Click me 1
Click me 2
Click me 3
</body>
</html>
The changes it makes from the original code:
Added id to each link. The number in this is written to the screen.
Changed Javascript to write the id of the link.
Someone at work jokingly sent out an email with a html file intended to crash your browser that was the following
<html>
<script type="text/javascript">
function crash(){
for(i=0;i<5000000001;i++){
document.write(i);
}
}
</script>
<body onload="crash();">
</body>
</html>
Anyways it doesn't do a great job of it in Chrome and a conversation arose that it created a friendly competition to see who could write javascript to make a page count to 5,000,000,000 as quickly as possible without causing the browser to become unresponsive or crash.
I came up with the following piece of javascript that is intended to be used in Chrome.
<html>
<script type="text/javascript">
function countToFiveBillion(counter, num){
if(num < 5000000000)
{
num++;
if(num % 18700 == 0){
counter.innerHTML = num;
setTimeout(function() {countToFiveBillion(counter, num)}, 1);
} else {
countToFiveBillion(counter, num);
}
}
}
function initiateCountDown()
{
var counter = document.getElementById("counter");
var num = +counter.innerHTML;
countToFiveBillion(counter, num);
}
</script>
<body onload="initiateCountDown();">
<div id="counter">0</div>
</body>
</html>
The reason that this will only run in chrome is that I'm using the setTimeout call to avoid creating a stackoverflow in chrome. (Chrome also allows you the largest stack for recursive calls out of all of the browsers).
Is there any way for me to make this count any quicker? I think that I can increase the amount counted a little before it causes an overflow (somewhere less than 100 though) The only stipulation is that is has to display as many numbers as possible as it counts.
Improved Code:
<html>
<script type="text/javascript">
var counter;
var num = 0;
function countToFiveBillion(){
if(num < 5000000000)
{
num++;
if(num % 18701 == 0){
setTimeout("countToFiveBillion()", 1);
counter.value = num;
} else {
countToFiveBillion();
}
} else {
counter.value = "number greater than 5 Billion";
}
}
function initiateCountDown()
{
counter = document.getElementById('counter');
countToFiveBillion();
}
</script>
<body onload="initiateCountDown();">
<input type="text" id="counter" value="0" />
</body>
</html>
Made count and element globabl
Switched to text input instead of div
moved update UI to after setting the callback
Don't use .innerHTML = ... to display the number. According to this test, setting the value property of an input element is more efficient.
<input type="text" id="counter" value="0" />
Instead of constructing a new function, I recommend to use global / local variables, and passing a function reference as an argument to setTimeout, or use setInterval at init.
Swap setTimeout("countToFiveBillion()",1) for setTimeout(countToFiveBillion,0).
Explanation: "countToFiveBillion()" is inefficient; First, the string gets converted to a function and called, then another function call follows. The suggested function runs only has to call a function, without creating new ones. It's also called a split second faster.
Lift the limit (I was able to increase 18701 to 20000). After lifting the limit to such a rounded number, I noticed that the counter value is updated between each time-out.
Fixed some errors in the implementation (replaced .innerHTML with .value at the else-block).
Relevant code:
<input type="text" id="counter" />
<script>
var counter, num = 0;
function countToFiveBillion(){
if(num < 5e9)
{
if(++num % 18701 == 0){
setTimeout(countToFiveBillion, 0);
counter.value = num;
} else {
countToFiveBillion();
}
} else {
counter.value = "number greater than 5 Billion";
}
}
function initiateCountDown(){
counter = document.getElementById('counter');
counter.value = num; //Init, show that the script is
countToFiveBillion();
}
window.onload = initiateCountDown;
</script>
Fiddle: http://jsfiddle.net/KTtae/
Webworker example, index.html
<!DOCTYPE HTML>
<html>
<head>
<title>5 billion</title>
</head>
<body>
<input type="text" id="counter" value="0" />
<script type="text/javascript" charset="utf-8">
var
iCounter = document.getElementById('counter')
, counter = new Worker('worker.js');
iCounter.value = 0;
counter.addEventListener('message', function (e) {
iCounter.value = e.data;
}, false);
</script>
</body>
</html>
worker.js:
for (var i = 0; i < 5e9; i++) {
if (i % 18701 === 0) {
postMessage(i);
}
}
The counting can be splited in multiple workers if needed.