Not sure why this isn't working - Javascript basic increment function - javascript

I am writing code to increment the most basic progress bar ever...... it just isn't working.
These are the variable used:
map.progress_bar = // the progress div that grows inside a container div that is the width of the screen (100%);
progress = 0;
state.window_width = // the width of the window or otherwise $(window).width();
setTimeout(function incProgress(){
if ( map.progress_bar.width() < state.window_width ) {
progress += 10;
map.progress_bar.css({
width: String(progress + '%')
});
console.log('progress: ', map.progress_bar.width());
console.log('window: ', state.window_width);
setTimeout(incProgress(), 300);
}
}, 300);
Please do not ask me to do setInterval. Please explain to me why on earth this does not work, I feel very unhappy.

setTimeout(incProgress(), 300);
You are calling the function and passing its return value (undefined) to setTimeout.
You need to pass a function to setTimeout.
Remove the ().

Related

if/else and setInterval

<script>
//when user clicks start button this function ensures all fields //are set to 0 and it
//sets the timer for the game (90seconds) and the second timer to //call showWord() every four seconds to display a new word
function startGame() {
numBadWordsField.innerHTML = '';
numGoodWordsField.innerHTML = '';
numWordsRight = 0;
numWordsWrong = 0;
correctWords = [];
showWord();
gameTimer = setInterval(gameTime, 1000);
timedWordDisplay = setInterval(showWord, 4000);
}
//this function is set to repeat every four seconds unless the user //types the word
//correctly in which case code in the checkWord() function resets setInterval then and a new word appears
function showWord() {
let randomNum = Math.floor(Math.random()*wordsLevelOne.length);
currentWord = wordsLevelOne[randomNum];
//i put all correctly typed words in an array to avoid them being repeated
//if the random word has been typed correctly and is in the array then i tell the
//program to repeat the function until a new word is found.
if (correctWords.includes(currentWord)) {
showWord();
} else {
wordDisplayBox.innerHTML = currentWord;
setInterval(changeBar, 500);
answerBox.focus();
}
}
//this function is called oninput as user types in the word. it works perfectly (i think it does anyways)
//however i cannot figure out how to give instructions in the event the user does not type the
//word correctly before the four seconds are up and the setInterval repeats. I would like to
//in that case increment the words wrong score and reset the fields to be ready for the next
//word to be displayed
function checkWord() {
let currentWordLen = answerBox.value.length;
if (wordDisplayBox.innerHTML === answerBox.value) {
clearInterval(timedWordDisplay);
numWordsRight++;
correctWords.push(currentWord);
numGoodWordsField.innerHTML = numWordsRight;
answerBox.value = '';
answerBox.focus();
wordDisplayBox.innerHTML = '';
showWord();
timedWordDisplay = setInterval(showWord, 4000);
} else if (answerBox.value === currentWord.substring(0, currentWordLen)) {
answerBox.style.borderColor = 'green';
} else {
answerBox.style.borderColor = 'red';
}
}
//different topic than above but i also researched how to make my progress bar fill slowly over the course
//of the four seconds. i have written the following function identically to that on
//w3schools and other code yet it does not work.
//Any ideas?
function changeBar() {
let proBar = document.querySelector('#progressBar');
var width = 1;
var id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
width++;
proBar.style.width = width + '%';
}
}
}
</script>
This project Im working on is a beginner level speed typing game that displays a different word for the user to type in less than four seconds.I have a setInterval that displays a different word every four seconds unless the user types the word correctly at which point the timer starts over then. What I am stumped at is how can I make it so that if the correct answer is not typed in before the interval resets (at the end of four seconds) the program knows to increment the 'wrong answer' score and to reset the input boxes for the next word just like when it is typed correctly. i have attached the parts of my code i think may be relevant. If anyone has any suggestions let me know. I am eager to learn. **I am not familiar yet with JQuery. Please describe any suggestions using vanilla JS
This feature should be implemented in the showWord function.
showWord is executed after 4 seconds have passed, which is when the time is up. Executing this function means the user has failed to type the word in time.
I would do something like this :
function showWord() {
// At this point, the user has lost. We perform the according operations
numWordsWrong++;
answerBox.value = '';
// etc.
// What follows is the rest of the function you've already implemented
let randomNum = Math.floor(Math.random()*wordsLevelOne.length);
// etc.
}
To answer your question about the progress bar, you are setting an interval to run changeBar every 500 milliseconds, which would cause the progress bar to reset every half second. If you want a delay before starting the progress bar use setTimeout.
In addition, you are running your progress bar to move 1% every 10 milliseconds which would result in the bar completing in 1 second. If you want the bar to complete in 4 seconds, set the id interval to run every 40 milliseconds.
Without seeing your css and html, I have to assume you're using the correct id names in your code but if nothing is happening at all, that could also be the cause.
I have looked at the W3Shools code you reference and I tried to replicate what you were trying to do and got this to work:
<html>
<head>
<style>
#myProgress {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 1%;
height: 30px;
background-color: #4CAF50;
}
</style>
</head>
<body>
<div id="myProgress">
<div id="myBar"></div>
</div>
</body>
<script>
function changeBar() {
let proBar = document.querySelector('#myBar');
var width = 1;
var id = setInterval(frame, 40);
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
width++;
proBar.style.width = width + '%';
}
}
}
setTimeout(changeBar, 100);
</script>
</html>
One solution can be to create a new function (ex : showWordBecauseTimeout) and call it in your setInterval instead of showWord. And call that function in showWord fct instead of in startGame fct.
So the new code would be something like :
function showWord() {
clearInterval(timedWordDisplay);
timedWordDisplay = setInterval(showWordBecauseTimeout, 4000);
// you also need to move the cleaning of the input in the showWord fct
// ...
}
function showWordBecauseTimeout() {
numWordsWrong++;
showWord()
}
Hope that it helps you :).

javascript scrollTop doesn't seem to work

I use a technique where I have a table within a div so as to limit the space covered by the table and scroll instead.
Within the table are checkboxes. These checkboxes effect how the table is rendered. When one is clicked, the table is re-rendered within the div. This always causes the scrollbar to go back to the top which is annoying.
So after I render the table in javascript I do a setTimeout call to asynchronously call a function that sets the scrollTop value back to where it was before the re-render.
Here's the code snipit in question:
Note: (ge() == geMaybe() == document.getElementById())
o.renderAndScroll = function() {
var eTestSection = geMaybe(o.id + '-testSection');
var scrollTop = 0;
if (eTestSection) {
scrollTop = eTestSection.scrollTop;
}
o.render();
if (eTestSection) {
setTimeout(
function() {
console.log('Scrolling from ' + ge(o.id).scrollTop + ' to ' + scrollTop);
ge(o.id).scrollTop = scrollTop;
console.log('Scrolled to ' + ge(o.id).scrollTop);
},
1000);
}
}
My console log output is this each time I change a checkbox state:
Scrolling from 0 to 1357
Scrolled to 0
Any other way to make this work? Note that I made the timeout a full second just to make sure the render was moved to the DOM by the time my scroll code is called. I am using chrome mainly but need it to eventually work cross-browser. I don't use jQuery. If I try to catch the onscroll event in the debugger or even log stuff from an onscroll handler, the chrome debugger crashes when the scrollbar is moved with the mouse.
The correct code is:
o.renderAndScroll = function(fForce) {
var scrollTop = 0;
var eTestSection = geMaybe(o.id + '-testSection');
if (eTestSection) {
scrollTop = eTestSection.scrollTop;
}
o.render(fForce);
setTimeout(
function() {
// re-lookup element after being rendered
var eNewTestSection = ge(o.id + '-testSection');
eNewTestSection.scrollTop = scrollTop;
},
1);
};

Transition animation bug

If i use in showAnimateWin property offsetHeight, animation work. example
function end( ) {
var top = ( window.innerHeight - win.clientHeight ) / 2,
left = ( window.innerWidth - win.clientWidth ) / 2;
win.style.top = top + "px";
win.style.left = left + "px";
}
function showAnimateWin( ) {
win.offsetHeight ;//here
win.classList.add("modal-window-animate");
end();
};
If i removed win.offsetHeight, animation work only one times. example
function showAnimateWin( ) {
win.classList.add("modal-window-animate");
end();
};
Why won't work without win.offsetHeight ?
The reason is probably because the win.offsetHeight; causes the method to wait for a few milliseconds before the transition can start again. If you put alert(1); instead of the win.offsetHeight; it will still work. You need to wait for the transition to complete before starting another animation.
UPDATE: Fiddle Link
This should work without having any delays (check fiddle):
window.setTimeout(function() {
showAnimateWin();
}, 25);

How to get width from animated div in jQuery

Thanks in advance for your support here. I have a simple code here but I wonder why it doesn't work.
This code below was put into a variable "percent"
var percent = $('#div').animate({width:80 + '%'},1000);
and I want to use the variable to become a text or content to a specific div. I tried to do it this way, however it doesn't work.
$('#val').text(percent); or $('#val').html(percent);
I tried to use the parseInt() function from JavaScript, but it doesn't work as well.
$('#web-design').text(parseInt(percent));
Do you have any suggestions or is this possible?
I am not sure if the line code it is correct
var percent = $('#div').animate({width:80 + '%'},1000);
To find the with property for #div I will do something like this
$('#val').text($("#div").css("width"))
or
$('#val').text($("#div").width())
The animate function does not return the changes to the element. To get the width you will have to use .width() but you will get it in pixel and not percentage.
var width = $('#div').width();
You can try this code:
$('#div1').animate({width:80 + '%'},{
duration:1000,
easing:'swing',
step: function() { // called on every step
$('#div1').text(Math.ceil($('#div1').width()/$('#div1').parent().width()*100) + "%");
}
});
This will print the Div-Width % as text in Div at every step of update.
You code is going to animate to 80% width in 1 second (1000 ms). You can increase the percentage width by 1% each iteration and update your #val at the same time until you hit 80. Below is the example based on 10000ms (10 secs), you can change the starting parameters such as duration, endWidth, startWidth to suit.
Demo: http://jsfiddle.net/zthaucda/
HTML:
<div class="my-anim-div"></div>
<button class="start-animating">Start animation</button>
<div id="val">Width will display here</div>
CSS:
.my-anim-div {
width:0%;
height:200px;
background-color:red;
}
Javascript including jQuery library:
var duration = 10000;
var endWidth = 80;
var startWidth = 0;
$('.start-animating').on('click', function () {
// work out the interval to make the animation in `duration`
var interval = duration / (endWidth - startWidth);
console.log(interval);
var myInterval = setInterval(function () {
// Increment the startWidth and update the width of the div and the display
startWidth++
// update div width
$('.my-anim-div').animate({
'width': startWidth + '%'
}, interval);
// update display
$('#val').text(startWidth + '%');
if (startWidth == 80) {
// then exit the interval
clearInterval(myInterval);
}
}, interval);
});
If you mean you want to get the current width of the div you can use clientWidth property:
$('#div')[0].clientWidth

Javascript fade in doesn't visibly animate

So I've created the following function to fade elements in and passed in a div that I want to fade in which in this case is an image gallery popup that I want to show when a user clicks an image thumbnail on my site. I'm also passing in a speed value (iSpeed) which the timeout uses for it's time value. In this case I'm using 25 (25ms).
I've stepped through this function whilst doing so it appears to be functioning as expected. If the current opacity is less than 1, then it is incremented and it will recall itself after the timeout until the opacity reaches 1. When it reaches one it stops fading and returns.
So after stepping through it, I take off my breakpoints and try to see it in action but for some reason my gallery instantly appears without any sense of fading.
var Effects = new function () {
this.Fading = false;
this.FadeIn = function (oElement, iSpeed) {
//set opacity to zero if we haven't started fading yet.
if (this.Fading == false) {
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
this.Fading = false;
return;
}
//otherwise, fade
else {
this.Fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
}
}
}
Here's where I'm setting up the gallery.
this.Show = function (sPage, iImagesToDisplay, oSelectedImage) {
//create and show overlay
var oOverlay = document.createElement('div');
oOverlay.id = 'divOverlay';
document.body.appendChild(oOverlay);
//create and show gallery box
var oGallery = document.createElement('div');
oGallery.id = 'divGallery';
oGallery.style.opacity = 0;
document.body.appendChild(oGallery);
//set position of gallery box
oGallery.style.top = (window.innerHeight / 2) - (oGallery.clientHeight / 2) + 'px';
oGallery.style.left = (window.innerWidth / 2) - (oGallery.clientWidth / 2) + 'px';
//call content function
ImageGallery.CreateContent(oGallery, sPage, iImagesToDisplay, oSelectedImage);
//fade in gallery
Effects.FadeIn(oGallery, 25);
}
Could anyone help me out?
Also, I'm using IE10 and I've also tried Chrome, same result.
Thanks,
Andy
This line:
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
calls Effects.FadeIn with the given arguments, and feeds its return value into setTimeout. This is exactly like foo(bar()), which calls bar immediately, and then feeds its return value into foo.
Since your FadeIn function doesn't return a function, that would be the problem.
Perhaps you meant:
setTimeout(function() {
Effects.FadeIn(oElement, iSpeed);
}, iSpeed);
...although you'd be better off creating that function once and reusing it.
For instance, I think this does what you're looking for, but without recreating functions on each loop:
var Effects = new function () {
this.FadeIn = function (oElement, iSpeed) {
var fading = false;
var timer = setInterval(function() {
//set opacity to zero if we haven't started fading yet.
if (fading == false) { // Consider `if (!this.Fading)`
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
clearInterval(timer);
}
//otherwise, fade
else {
fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
}
}, iSpeed);
};
};
Your code has a lot of problems. The one culpable for the element appearing immediately is that you call setTimeout not with a function but with the result of a function, because Effects.FadeIn will be executed immediately.
setTimeout(function(){Effects.FadeIn(oElement, iSpeed)}, iSpeed);
will probably act as you intend.
But seriously, you probably should not re-invent this wheel. jQuery will allow you to fade elements in and out easily and CSS transitions allow you to achieve element fading with as much as adding or removing a CSS class.
T.J. and MoMolog are both right about the bug: you're invoking the Effects.FadeIn function immediately before passing the result to setTimeout—which means that Effects.FadeIn calls itself synchronously again and again until the condition oElement.style.opacity >= 1 is reached.
As you may or may not know, many UI updates that all take place within one turn of the event loop will be batched together on the next repaint (or something like that) so you won't see any sort of transition.
This jsFiddle includes the suggested JS solution, as well as an alternate approach that I think you may find to be better: simply adding a CSS class with the transition property. This will result in a smoother animation. Note that if you go this route, though, you may need to also include some vendor prefixes.

Categories

Resources