I'm starter in JavaScript and I try to make simple code to print numbers (0-100) , but with pause in printing, for every next number(for exp. 3 seconds pause).
Code doesn't work properly... It waits 3 seconds and print the last number (100 in my case). Can you help me, where is my mistake?
This is the code:
<html>
<head>
<script type="text/javascript">
function funkcija_polnac()
{
var i = 0;
while (i <= 100) {
setTimeout(function(){ document.write(i + '%');}, 3000);
i++;
}
}</script>
</head>
<body>
<div style="margin: 0px auto;" onclick="funkcija_polnac()">Start</div>
</body>
</html>
What your code does is schedule 101 function callbacks, all of which will happen one right after another about three seconds after the code runs, and all of which will use the i variable, not its value as of when the function was created. So after three seconds you get 101 iterations of the value 101. This is because the functions you're creating are "closures over" the i variable (more accurately, the context in which the variable was created), and so they have an enduring reference to the variable and see its value as of when they use it, not as of when they were created. More about closures on my blog: Closures are not complicated
Or at least, that's what you'd see if it weren't that document.write, when used after initial parsing, blows away the page entirely. Basically: Don't use document.write. :-)
To fix it, you would schedule a single call to a function that, once it's run, schedules the next call. And you'd use the DOM or similar rather than document.write to see the output.
Example:
// NOTE: I used 30ms rather than 3000ms so it runs faster
var i = 0;
showOne();
function showOne() {
display(i);
++i;
if (i <= 100) {
setTimeout(showOne, 30); // You'd really want 3000
}
}
// Displays the given message by adding a paragraph element to the page
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
p {
padding: 0;
margin: 0;
font-family: sans-serif;
}
Well, you are running your while before the timeout happens. Try this
<html>
<head>
<script type="text/javascript">
function funkcija_polnac(i)
{
document.getElementById("output").innerHTML = i + "%";
if (--i > -1) {
setTimeout(function () { funkcija_polnac(i); }, 3000);
}
}
</script>
</head>
<body>
<div style="margin: 0px auto;" onclick="funkcija_polnac(5)">Start</div>
<div id="output"></div>
</body>
</html>
Related
I have to "Create a function, outside of the jQuery ready function, which increments the user's score when called and updates the HTML in span#score. I have the Variable. I have the function started but am not sure how to finish it so that it will change the text. I'm also not sure that I'm calling the function right in my .ready section.
I have this as part of a multiple question I put out a few days ago, but I really asked that wrong, too broad. I need to figure this out tonight. It's due at midnight but I'm sure he'll take it a little late. I think this is all the code I need to post. I think the rest would just be in the way, but let me know if you need it.
<script>
var mole='<img src="img/mole.jpg"/>';
var score=0;
$(document).ready(function(){
$("#score").click(increment);
}); //end.ready
function increment(){
score+=1
}; //end increment
</script>
Any help would be a true blessing at this point.
Your increment() function is indeed increasing the score; all you need to do is actually output this back on the page. This can be done with $("#score")[0].innerHTML = score, as is seen in the following example:
var score = 0;
$(document).ready(function() {
$("#score").click(increment);
});
function increment() {
score += 1;
$("#score")[0].innerHTML = score;
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="score">0</div>
The [0] is needed because $(#score) (although targeting an ID) returns a NodeList collection of objects, and you want to access the first object in this list.
Hope this helps! :)
You need to return the increased value from the function. Also use text method to show the text in the DOM element
<!-- begin snippet: js hide: false console: true babel: false -->
var score = 0;
function increment() {
score += 1
return score;
};
$(document).ready(function() {
$("#score").click(function() {
var getIncreasedValue = increment();
$("#textDisplay").text(getIncreasedValue)
});
}); //end.ready
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="textDisplay"></div>
<button id="score">Click</button>
Since the execution context inside the jQuery.click() is set to individual DOM Element inside jQuery's elements array, you can also do something like this:
$(function() {
$('span#counter').on('click', increment);
// or $('span#counter').click(increment);
})
var score = 0;
function increment() {
this.innerHTML = ++score + '';
}
span#counter {
padding: 15px;
margin: 15px;
line-height: 10px;
cursor: pointer;
border: 1px solid #ddd;
user-select: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<span id="counter">0</span>
How I update the DOM in html meanwhile I'm executing a "while sentece".
Look the example below
<html>
<body>
<input type="text" id="element" >
<input type="submit" id ="run" value="run">
<script>
function contar(){
var contador=0;
while( contador<10){
setTimeout(function(){
$('#element').val( contador );
},1000);
//I use sleep or setTimeout to try to see the values
//if put its in the input.
console.log("contando");
contador++;
}
}
function sleep(seconds){
var e = new Date().getTime() + (seconds * 1000);
while (new Date().getTime() <= e) {
}
}
$('#run').bind('click',contar);
</script>
</body>
</html>
Context:
I have a process logic inside a while loop, this process, generates data that I use to show in a view through of jquery or other way. When I try to update the content in real time, it's mean that when I try to change some value inside a while loop, it does not work .All I see is the last value that generates the process logic. So I wanna see all changing data.
For example in the code above, I would like see 1 ,2,3,.., value to value.
The Problem with your code is, that your while loop
while(contador<10){
setTimeout(function(){
$('#element').val( contador );
},1000);
contador++;
}
will start the inner function $('#element').val( contador ); 10 times with the same delay of 1000ms instead of executing each code after next 1000ms.
The reason for this is, that your program won't wait for 1000ms when calling setTimeout(); - it just starts an other "thread-like" thing, which will be executed after 1000ms. But the program itself will continue straight.
so I think you're looking for something like:
// note these extra function
function updateValue(val){
setTimeout(function(){
$('#element').val( val );
},1000 * val);
}
. . .
var contador = 0;
while(contador<10){
updateValue(contador);
contador++;
}
Here is a working example: jsfiddle
The extra function is needed to be sure that the right number is printed. If you do it in place inside the while loop, the number will always be your maximum.
I've a jsp page which sets 'timestamp' attribute to certain HTML elements. I use the value of these 'timestamp' to display time elapsed in the format - "updated 10 seconds ago" (as tooltips)
I've created a static HTML page for the demonstration of my issue.
This is my code:
<html>
<head>
<script type = "text/javascript">
function setTime() {
var currentDate = new Date();
var elem = document.getElementsByClassName('supermaxvision_timestamp');
if(elem) {
for (var i = 0; i < elem.length; i++) {
var timestamp = elem[i].getAttribute('timestamp');
if(timestamp) {
var startTimestamp = new Date();
startTimestamp.setTime(timestamp)
var difference = currentDate.getTime() -startTimestamp.getTime();
elem[i].innerHTML = difference + " milliseconds";
}
}
}
setInterval(setTime, 1000);
}
</script>
</head>
<body>
<div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>
<button onclick="setTime()">start</button>
</body>
</html>
you can just copy paste this code into a text file and open it in a browser (click 'start' button only once).
The problem is that initially the values of my div will update once every second ( as the code - setInterval(setTime, 1000)). But slowly the update interval decreases and values gets updated instantaneously. And within a minute the browser stops responding.
I'm not calling setInterval from within the loop. What is possibly wrong here?
Also, this code doesn't work in IE.
setInterval(fn, ms) says run fn every ms milliseconds, from now until I clear this interval. But on each call, you set a new interval, identical to the last.
So simply change setInterval to setTimeout which does not repeat, and only calls the function provided once. setTimeout can emulate setInterval by calling a function that sets a new timeout recursively. If you do that with intervals, you schedule more and more intervals that never stop. And each time it calls itself, the number of scheduled intervals double. It gets out of hand quickly...
Alternatively, you can move the setInterval out of the setTime function and only call it once, which will keep it being called every second. Like say:
// button calls this.
function startTime() {
setInterval(setTime);
}
function setTime() {
// all that code, but minus the setInterval at the end
}
You're calling setInterval recursively. Every time a new interval is created, that interval creates a new interval. Eventually the browser cannot handle it.
Maybe you would rather something like this?
<button onclick="setInterval(setTime, 1000)">start</button>
setInterval begins a repeating function - as it is right now setTime does it's loop and logic then calls setTimeout every second, each setTimeout call then starts another repeated call to itself every second. if you use setTimeout instead, it will be called once only, but my suggestion would be that instead you simply run setInterval outside your function declaration, like:
<html>
<head>
<script type = "text/javascript">
function GEBCN(cn){
if(document.getElementsByClassName) // Returns NodeList here
return document.getElementsByClassName(cn);
cn = cn.replace(/ *$/, '');
if(document.querySelectorAll) // Returns NodeList here
return document.querySelectorAll((' ' + cn).replace(/ +/g, '.'));
cn = cn.replace(/^ */, '');
var classes = cn.split(/ +/), clength = classes.length;
var els = document.getElementsByTagName('*'), elength = els.length;
var results = [];
var i, j, match;
for(i = 0; i < elength; i++){
match = true;
for(j = clength; j--;)
if(!RegExp(' ' + classes[j] + ' ').test(' ' + els[i].className + ' '))
match = false;
if(match)
results.push(els[i]);
}
// Returns Array here
return results;
}
function setTime() {
var currentDate = new Date();
var elem = GEBCN('supermaxvision_timestamp');
if(elem) {
for (var i = 0; i < elem.length; i++) {
var timestamp = elem[i].getAttribute('timestamp');
if(timestamp) {
var startTimestamp = new Date();
startTimestamp.setTime(timestamp)
var difference = currentDate.getTime() -startTimestamp.getTime();
elem[i].innerHTML = difference + " milliseconds";
}
}
}
}
</script>
</head>
<body>
<div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>
<button onclick="setInterval(setTime, 1000)">start</button>
</body>
</html>
Also, the reason this is not working in IE is that it does not properly support the getElementsByClassName method of document. I found that out here: IE 8: Object doesn't support property or method 'getElementsByClassName' and Rob W also gives a good explanation there, but for a quick answer I have modified my code above to work in IE, using querySelectorAll
Derp, thats a jQuery method Chris, why would you just assume people use jQuery. getElementsByClassName & IE8: Object doesn't support this property or method includes an answer from ascii-lime which implements it's own version of getElementsByClassName. There no benefit to me copying all the code to here, but go have a look if you don't want to use jQuery.
OK, I just said there was no point, but I've copied all the code here anyway, above is a working, tested (on ie and ff) example of what you want
Really a newbie question but I can't seem to find the answer. I need to have this html file show a bunch of random numbers, separated by 1 second intervals. For some reason (maybe obvious) it is only showing me the last one unless I have 1 alert after each random number generated. How can I correct this?
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var randomnumber
var message
function placePossibleWinner()
{
randomnumber=Math.floor(Math.random()*11);
message="Teste ";
message=message.concat(randomnumber.toString());
document.getElementById("WINNER").innerHTML=message;
//alert(".")
}
</script>
</head>
<body>
<script type="text/javascript">
function runDraw()
{
var i=1
alert("start")
while (i<20)
{
setTimeout("placePossibleWinner()",1000)
i++
}
}
</script>
<h1>H Draw</h1>
<p id="WINNER">Draw</p>
<p></p>
<button onclick="runDraw()">Get me winner!</button>
</body>
</html>
Thanks in advance for any answers/comments.
The problem is all your setTimeouts are being triggered at the same time. Adding alerts pauses the JavaScript execution, so you see each number. Without that, after 1 second, all 19 setTimeouts run (one after another) and you just see one number (the screen is updated so fast, you just see one).
Try using setInterval instead.
function runDraw() {
var i = 1;
var interval = setInterval(function(){
if(i < 20){
placePossibleWinner();
i++;
}
else{
clearInterval(interval);
}
}, 1000);
}
This will run the function once every second, until i is 20, then it will clear the interval.
I believe you want setInterval instead. using setTimeout in a loop will just queue up 20 calls immediately and they will all fire at once 1 second later. Also, you are setting the innerHTML of the p which will overwrite any previous text.
function placePossibleWinner() {
// add a var here, implicit global
var randomnumber=Math.floor(Math.random()*11);
// add a var here, implicit global
message="Teste " + randomnumber + '\n'; // new line
document.getElementById("WINNER").innerHTML += message; // concat, don't assign
}
function runDraw() {
var counter = 1;
var intervalID = setInterval(function () {
if (counter < 20) {
placePossibleWinner();
counter++;
} else {
clearInterval(intervalID);
}
}, 1000);
}
You are resetting your message in your functions and you are calling placePossibleWinner() the wrong way... you want to use setInterval. Below is a modification of your html/javascript
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var randomnumber;
var message = "Teste ";
var timesCalled = 0;
var funtionPointer;
function placePossibleWinner()
{
timesCalled++;
randomnumber=Math.floor(Math.random()*11);
message=message.concat(randomnumber.toString());
document.getElementById("WINNER").innerHTML=message;
if (timesCalled > 20)
{
clearInterval(functionPointer);
}
}
</script>
</head>
<body>
<script type="text/javascript">
function runDraw()
{
var i=1
alert("start")
functionPointer = setInterval(placePossibleWinner,1000)
}
</script>
<h1>H Draw</h1>
<p id="WINNER">Draw</p>
<p></p>
<button onclick="runDraw()">Get me winner!</button>
</body>
</html>
To start with,
setTimeout("placePossibleWinner()",1000)
should be
setTimeout(placePossibleWinner,1000)
The parameter to setTimeput should be a reference to a function. See JavaScript,setTimeout
I am trying to make each number displayed clickable. "1" should alert() 80, "2" should produce 60, etc.
However, when the alert(adjust) is called, it only shows 0, not the correct numbers. However, if the commented out alert(adjust) is uncommented, it produces the correct number on page load, but not on clicking.
I was wondering why the code inside addEvents cannot access the previously defined variable adjust.
<html>
<head>
<script type="text/javascript" charset="utf-8" src="mootools.js"></script>
<script type="text/javascript" charset="utf-8">
window.addEvent('domready', function() {
var id_numbers = [1,2,3,4,5];
for(var i = 0; i<id_numbers.length; i++) {
var adjust = (20 * (5 - id_numbers[i]));
// alert(adjust);
$('i_' + id_numbers[i]).addEvents({
'click': function() {
alert(adjust);
}
});
}
});
</script>
</head>
<body>
<div id="i_1">1</div>
<div id="i_2">2</div>
<div id="i_3">3</div>
<div id="i_4">4</div>
<div id="i_5">5</div>
</body>
</html>
Thanks.
You are having a very common closure problem in that for loop.
Variables enclosed in a closure share the same single environment, so by the time the click callbacks are called, the for loop would have run its course, and the adjust variable will be left pointing to the last value it was assigned.
You can solve this with even more closures, using a function factory:
function makeClickHandler(adjust) {
return function() {
alert(adjust);
};
}
// ...
for(var i = 0; i<id_numbers.length; i++) {
var adjust = (20 * (5 - id_numbers[i]));
$('i_' + id_numbers[i]).addEvents({
'click': makeClickHandler(adjust)
});
}
This can be quite a tricky topic, if you are not familiar with how closures work. You may to check out the following Mozilla article for a brief introduction:
Mozilla Dev Center: Working with Closures