setInterval and clearInterval not working - javascript

I am trying to make a dynamic progress bar which starts from 1% width and goes to 100% width;
Here is the function
const dynamicBar = (id)=>{
let bar = document.getElementById(id);
let width = 1;
let id= setInterval(frame,10);
function frame(){
if(width>=100){
clearInterval(id);
}
else{
bar.style.width = width + "%";
width++;
}
}
};
And the html part:
<div class="w3-light-grey">
<div class="w3-red" style="width:20%;height:20px;" id="bar1">
</div>
</div>
<button onClick="dynamicBar('bar1')" class="w3-button">Click Me</button>
but the function does not work. It works if i use var instead of let but i want to know how to do this using let keyword.

let doesn't allow you to define something twice, so you need to use a different name. You had id for both your parameter and in line 5, which isn't allowed with let.
For example,
let var1 = true;
let var1 = false;
would throw an error, since it defines var1 twice. However, you can change the value.
let var1 = true;
var1 = false;
The code block above would work just fine. let is used so that you don't accidentally override a variable in a big program.
const dynamicBar = (idName) => {
let bar = document.getElementById(idName);
let width = 1;
let id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
bar.style.width = width + "%";
width++;
}
}
};
<div class="w3-light-grey">
<div class="w3-red" style="width:20%;height:20px;background-color:red;" id="bar1">
</div>
</div>
<button onClick="dynamicBar('bar1')" class="w3-button">Click Me</button>

when you are using var, your first Id is been overridden by your second id assignment, so it will not throw an error. but when you use let, it tends to keep the code integrity and says no.
as an example
var foo = "something"
var foo = "another thing"
console.log(foo) //another thing
but
let foo = "something"
let foo = "another thing"
give you this, "Identifier 'foo' has already been declared"
one more thing, is that use const for constant values.
instead of this
let id = setInterval(frame, 10);
use
const interval = = setInterval(frame, 10);
make sure you clear interval inside fame
clearInterval(interval)
and your code will start working

Related

How to make clearInterval() work in JavaScript

I want to make an element (id=runner) move across the page by n pixels after a mouseover event, then stop at a certain position (left = 2000px), using setInterval() to repeatedly call move_left(), then clearInterval() when left == 200px. I can make the element move, but when I look in developer tools it never stops - left continues to increase. I am pretty new to JavaScript/HTML/CSS. How do I make it stop?
Relevant code:
<script>
function runner_go()
{
var load_time = performance.now();
const go = setInterval(move_left,20);
}
function move_left()
{
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position,10) + 17 + "px";
if (parseInt(runner_position,10) > 2000)
{
clearInterval(go);
}
}
</script>
</head>
<body style="background-color:gray;" onmouseover = "runner_go();">
<div>
<h1>Running!</h1>
</div>
<img src="images/runner_l.png" alt ="running man" style="position:relative; visibility:hidden;" id = "runner"/>
</body>
You need to create the var 'go' outside the method cause of the scope, also if you let on the 'body' the 'onmouseover' it will set the interval everytime.
Try this code to test:
<head>
<script>
let go = null;
function runner_go()
{
var load_time = performance.now();
go = setInterval(move_left,20);
}
function move_left()
{
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position,10) + 17 + "px";
if (parseInt(runner_position,10) > 2000)
{
clearInterval(go);
}
}
</script>
</head>
<body style="background-color:gray;" onclick = "runner_go();">
<div>
<h1>Running!</h1>
</div>
<img src="images/runner_l.png" alt ="running man" style="position:relative; visibility:hidden;" id = "runner"/> </body>
Problem -
You declared the interval variable as a constant within another function which is not accessible by the move_left function
So just move your interval variable to global scope (outside the function) and it should work
let go;
function runner_go() {
var load_time = performance.now();
go = setInterval(move_left, 20);
}
function move_left() {
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position, 10) + 17 + "px";
if (parseInt(runner_position, 10) > 2000) {
clearInterval(go);
}
}
sample on how intervals and clearIntervals work
let interval, i = 1;
function start() {
interval = setInterval(log, 1000);
}
function log() {
if (i >= 5) clearInterval(interval);
console.log(`Test ${i}`);
i++
}
start();

Best performance Javascript conditionals based on countdown timer

I am currently working on a project that is showing and displaying DOM elements based on a countdown timer. There is another function calling this one every second.
Here is a code sample:
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x >= 0.0 && x < 30.0) {
document.getElementById('thing1').style.display = 'block';
document.getElementById('thing2').style.display = 'none';
}
else if (x >= 30.0 && x < 60.0) {
document.getElementById('thing1').style.display = 'none';
document.getElementById('thing2').style.display = 'block';
}
x++;
}, 1000);
}
I'm trying to increase performance, and I'm doing this by trying to reduce the number of DOM requests and looking at alternative ways to fire code based on the countdown timer.
Something like
function eventsOnTimer(id1, id2, ms) {
let toggle = false, thing1 = document.getElementById(id1), thing2 = document.getElementById(id2);
const interval = setInterval(() => {
if(toggle){
thing1.style.display = 'block';
thing2.style.display = 'none';
} else{
thing1.style.display = 'none';
thing2.style.display = 'block';
}
toggle = !toggle;
}, ms);
}
eventsOnTimer('thing1', 'thing2', 30000);
You can store all of nodes references before run your timer to dicrease DOM access time (getElementById).
After that, using className instead of style property will be faster. You juste need declared an specific CSS rule per state.
I propose to you an generic function to set automatically all of your nodes with the same CSS class name.
JS
var nodeArray = [];
var max_node = 2;
function storeNodeRef() {
for(var i =1; i <= max_node; i++) {
nodeArray.push( document.getElementById("thing"+i)); // Your nodes are declared with ID thing"X". "X" is a numeric value, set "max_node" with the latest "X" value.
}
eventsOnTimer();
}
function setNodeClass(nodeClassName) {
var i = 0;
while(i < max_node) {
nodeArray[i++].className = nodeClassName;
}
}
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x==30 || x == 60) { // declare here your different state, you can use multiple if/elseif or multiple switch case.
setNodeClass('hide myClass'+x); // Param : new className
}
x++;
}, 1000);
}
storeNodeRef();
CSS
.process > div, .hide {display:none;}
#thing2.myClass30, #thing1.myClass60, .process > div.show {display:block; }
HTML EXAMPLE
<div class="process">
<div id="thing1" class="show" >Hello World 1</div>
<div id="thing2">Hello World 2</div>
</div>

Get value of element once then keep that value static

I am using
function expand(btn) {
var box = btn.parentNode.parentNode,
ipsum = box.getElementsByTagName("p")[0],
textSize = window.getComputedStyle(ipsum, null).getPropertyValue('font-size'),
lineHeight = window.getComputedStyle(ipsum, null).getPropertyValue('line-height'),
boxWidth = window.getComputedStyle(box, null).getPropertyValue('width'),
initialHeight = window.getComputedStyle(box, null).getPropertyValue('height'),
numText = parseInt(textSize),
numWidth = parseInt(boxWidth),
numHeight= parseInt(initialHeight);
if(box.style.height == "150px"){
box.style.height = "40px";
ipsum.style = "display:none";
}
else{
box.style.height = "150px";
ipsum.style = "display:inline";
}
console.log(lineHeight);
}
to get the initial height value of an element the only problem is that the element height changes frequently, but the first value obtained is always correct how can i get the initial value and keep it static?
how do i only store the value in the variable once, i need it in a variable to do calculations but as the value keeps changing i am getting the wrong number outputs.
You can refactor the function to store the initialHeight in a "private" variable the first time it's run:
var expand = (function() {
var initialHeight;
// Return a function that holds initialHeight in a closure
return function (btn) {
// Get box before setting/getting initialHeight
var box = btn.parentNode.parentNode;
// Set initialHeight only if undefined
initialHeight = initialHeight || window.getComputedStyle(box, null).getPropertyValue('height');
// Do other variables
var ipsum = box.getElementsByTagName("p")[0],
textSize = window.getComputedStyle(ipsum, null).getPropertyValue('font-size'),
lineHeight = window.getComputedStyle(ipsum, null).getPropertyValue('line-height'),
boxWidth = window.getComputedStyle(box, null).getPropertyValue('width'),
numText = parseInt(textSize),
numWidth = parseInt(boxWidth),
numHeight= parseInt(initialHeight);
if(box.style.height == "150px"){
box.style.height = "40px";
ipsum.style.display = "none";
} else {
box.style.height = "150px";
// If ipsum is a P, probably better to use "" (empty string) here
// so it returns to its default or inherited value
// ipsum.style.display = "inline";
ipsum.style.display = "";
}
console.log(lineHeight);
}
}());
The above is a proper refactoring, tested with the following markup:
<style type="text/css">
#box {border: 1px solid blue;}
#notBox {border: 1px solid red;}
#ipsum {border: 1px solid yellow;}
</style>
<div id="box">box
<div id="notBox">notBox
<input type="button" onclick="expand(this)" value="Expand…">
<p id="ipsum">ipsum</p>
</div>
</div>
Can you set it as an attribute? Something like:
// set the value once some place
box.setAttribute('data-init-height', window.getComputedStyle(…)… );
// when setting the initial height, check for the attribute first
initialHeight = box.getAttribute('data-init-height') || window.getComputedStyle(…)…;
Follow-up:
see fiddle
Each time you execute the function expand, you got a new value for initialHeight.
All that you need is to record it in a closure, with a hash if you're having more than 1 btn to handle, valued with arrays if you'd like to record multi heights for each btn. Just like this:
// predefine the function expand for furthre usage.
var expand;
(function() {
/*
having arrays as value, indexed like this:
{
<btn_1_id> : [<firstHeight>, <2nd Height>, ...],
<btn_2_id> : [],
...
}
*/
// Let's assume every btn is having an id. You may think another way yourself it they don't.
var initialHeightForMultiBtns = {};
expand = function(btn) {
// ...blablabla
initialHeightForMultiBtns[btn.id] = initialHeightForMultiBtns[btn.id] || [];
initialHeightForMultiBtns[btn.id].push(window.getComputedStyle(box, null).getPropertyValue('height'));
console.log(initialHeightForMultiBtns[btn.id][0]); // the real initialized height for the given btn.
// ...blablabla
}
})()
expand(btn_1); // let's expand btn_1 here.
Good luck.

window scroll don't work properly

this is my code JS
var elem3 = document.createElement('DIV');
elem3.setAttribute('id', 'eye');
elem3.style.display = "block";
elem3.style.width = "100px";
elem3.style.height = "100px";
elem3.style.zIndex = "301";
elem3.style.position = "absolute";
elem3.style.top = "0px";
elem3.style.left = "0px";
document.body.appendChild(elem3);
var danger, up = 0;
window.onscroll = function(e) {
up += 10;
document.getElementById('eye').style.top = up + "px";
}
function check() {
danger = setInterval(function() {
if (document.getElementById('eye').style.top >= 2000 + "px") {
location.href = "http://www.google.com";
clearInterval(danger);
}
})
};
check();
I want to create a div (eye) and with scroll I want that this div fall by 10px.1 scroll=10px, 10 scroll=100px. If the top of eye is greater then 2000px this will redirect the page. But this don't work because when I begin scroll, the page redirect automatically and the div don't scroll to 2000px.
if (document.getElementById('eye').style.top>=2000+"px"){
That check is wrong, the check is a string comparison, not a number comparison.
You should be using parseInt to get the number value of the position.
if (parseInt(document.getElementById('eye').style.top,10)>=2000) { ...
Why are you checking the style when the variable up should hold the value?
if (up>=2000){ ...
Don't use window.onscroll=function(e){up+=10;document.getElementById('eye').style.top=up+"px";}
1) use scrollTop and added delay in setInterval.
2) Your "if" not work, use integer instead of string
Try this:
var elem3=document.createElement('DIV');
elem3.setAttribute('id','eye');
elem3.style.display="block";
elem3.style.width="100px";
elem3.style.height="100px";
elem3.style.zIndex="301";
elem3.style.position="absolute";
elem3.style.top="0px";
elem3.style.left="0px";
document.body.appendChild(elem3);
var danger, up=0;
window.onscroll=function(e){
up = window.scrollTop() + 10; //or `up = window.scrollTop();`
document.getElementById('eye').style.top = up +"px";
};
function check(){
danger = setInterval(function(){
if (parseInt(String(document.getElementById('eye').style.top).replace(/[a-zA-Z]/g)) >= 2000){
location.href="http://www.google.com";
clearInterval(danger);
}
}, 100);//Added delay
};
check();

javascript array cycling only first var

I am using javascript to cycle through an array of urls within an iframe and so far when the prev or next buttons are pressed it jumps to the first var in the array and both prev and next functions end. Any ideas?
<iframe id="myFrame" src="http://startpage.com" width="484px" height = "424px"></iframe>
<button onclick = "prevPage(); ">Prev</button>
<button onclick = "nextPage(); ">Next</button>
<script>
var sites=new Array();
sites[0]="http://site1.html";
sites[1]="http://site2.html";
sites[2]="http://site3.html";
sites[3]="http://site4.html";
function nextPage() {
var number = document.getElementById("myFrame").src;
number = number.substring(number.length - 4 ,number.length-3);
number = parseInt(number) + 1;
document.getElementById("myFrame").src=sites[0];
}
function prevPage() {
var number = document.getElementById("myFrame").src;
number = number.substring(number.length - 3 ,number.length-4);
number = parseInt(number) - 1;
document.getElementById("myFrame").src=sites[0];
}
</script>
Why are you using the URL as your 'position' storage? It'd be FAR easier to just use a variable:
var curPos = 0;
function nextPage() {
curPos++;
if (curPos >= sites.length) {
curPos = 0;
}
document.getElementById('myframe').src = sites[curPos];
}
function prevPage() {
curPos--;
if (curPos < 0) {
curPos = sites.length - 1;
}
document.getElementById('myframe'.).src = sites[curPos];
}
If I understood your problem correctly I think all you need to do is use document.getElementById("myFrame").src=sites[number]; instead of document.getElementById("myFrame").src=sites[0];
May be
document.getElementById("myFrame").src=sites[number-1];
is what you are trying to do in both functions.

Categories