I've been wrestling with a timing issue in my code for a few nights now, and can't come up with the correct solution.
Psuedo code description:
//event listener on button trigger a die roll each time it is clicked
// call animation function
//generate random values x number of times
//display each result with setTimeout
//run code to determine final "settled upon" value and display results
HTML:
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<head>
<title>Make Cards</title>
</head>
<body>
<p>Total:<span id="total"></span></p>
<div id="contain">
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<br>
<button id="rollBtn">Roll</button>
<input type="number" value = "1" min="1" max="6" id = "numDice">
</div>
</body>
</html>
Javascript:
var diceValue = ["⚀", "⚁", "⚂", "⚃", "⚄",
"⚅"];
var dice = document.querySelectorAll(".die");
// select number of dice
var numDice = document.querySelector("#numDice");
// convert string to value
var newNumDice = Number(numDice.value);
var roll = document.querySelector("#rollBtn");
var total = document.querySelector("#total");
// make animation function
// call animation function
init();
function init(){
displayDice();
}
//THIS IS THE BUTTON LISTERNER
roll.addEventListener("click", function(){
//THIS SHOULD RUN BEFORE THE REST OF THE FUNCTION (BUT DOESN'T SEEM TO)
animate();
var subTotal = 0;
for (var i = 0; i < newNumDice; i++){
var value = generateRandomDice()
dice[i].innerHTML = diceValue[value];
subTotal = subTotal + (value+1);
total.innerHTML = subTotal;
}
for (var i = 0; i < 6; i++){
dice[i].style.color = "black";
}
})
numDice.addEventListener("click", function(){
total.innerHTML = "-";
newNumDice = Number(numDice.value);
resetDice();
displayDice();
// console.log(Number(numDice.value));
})
function resetDice(){
for (var i = 0; i < diceValue.length; i++){
dice[i].innerHTML = "";
}
}
// only display chosen number of dice
function displayDice(){
for (var i = 0; i < newNumDice; i++){
dice[i].innerHTML = diceValue[i];
}
}
function generateRandomDice(){
var dieSide = Math.floor(Math.random() * 6);
return dieSide;
}
//ATTEMPT AT WRITING CODE FOR ANIMATION
function animate(){
for (var i = 0; i < 50000; i++){
var ani = setTimeout(rolling, 650);
}
}
function rolling(){
for (var i = 0; i < newNumDice; i++){
var value = generateRandomDice()
dice[i].innerHTML = diceValue[value];
dice[i].style.color = "grey";
}
}
Not sure what is going on, but it appears to me that the animate(); code is not run until the rest of eventListener is finished. Any help is great, thank you.
The issue is that you are waiting for asynchronous code to finish before you execute synchronous code. Every time you call setTimeout, it is storing the function to call for when it's ready to be called (which is 650 ms from 'now'!).
To fix, you can await for your animation to finish. Here's how I got it working on your codepen:
Change animate to:
function animate() {
return new Promise((resolve, reject) => {
for (let i = 0; i < 50000; i++) {
setTimeout(() => {
rolling();
if(i == 49999)
resolve();
}, 650);
}
});
}
and then you can await for the Promise to resolve by changing your click listener to this:
roll.addEventListener("click", async function() {
await animate();
var subTotal = 0;
for (var i = 0; i < newNumDice; i++) {
var value = generateRandomDice();
dice[i].innerHTML = diceValue[value];
subTotal = subTotal + (value + 1);
total.innerHTML = subTotal;
}
for (var i = 0; i < 6; i++) {
dice[i].style.color = "black";
}
});
The result showing afterward was correct for me.
Hope that helps!
Related
I'm doing some exercises and come across where I can't pass the value from the input box to a function inside a script, I don't really know what I have done wrong, I tried different things but didn't really work out. How can I make it work? I want to able to enter a number then press a button so that it prints pyramid according to given number, here is my code :
window.onload = function() {
let aantalLijnen = parseInt(document.getElementById('number').value);
document.getElementById("button").onclick = stars();
function stars() {
for (var i = 1; i <= aantalLijnen; i++) {
var row = '';
for (var j = 1; j <= i; j++) {
row += '*';
}
console.log(row);
}
}
};
<p>Give a number betweeen 2 and 10
<input type="number" id='number'>
<button id="button">Click</button></p>
You're calling stars() and assigning the result to the onclick handler.
You need to pass the function itself...
document.getElementById("button").onclick = stars;
Or just create an anonymous function directly...
document.getElementById("button").onclick = function() {
...
}
As pointed out by #j08691, you are setting the value of aantalLijnen on the page load.
Instead you want to get the value at the time the function runs, so you need to move it into the function itself...
window.onload = function() {
document.getElementById("button").onclick = function () {
let aantalLijnen = parseInt(document.getElementById('number').value);
for (var i = 1; i <= aantalLijnen; i++) {
var row = '';
for (var j = 1; j <= i; j++) {
row += '*';
}
console.log(row);
}
}
};
<p>Give a number betweeen 2 and 10
<input type="number" id='number'>
<button id="button">Click</button></p>
you have to get the value from input every time you click on the button
window.onload = function () {
const numberElem = document.getElementById('number');
document.getElementById("button").addEventListener('click', stars);
function stars() {
let aantalLijnen = parseInt(numberElem.value);
for (var i = 1; i <= aantalLijnen; i++) {
var row = '';
for (var j = 1; j <= i; j++) {
row += '*';
}
console.log(row);
}
}
};
Besides what already said by others
Don't use onclick handlers. Stick to cumulative listeners with addEventListener
You could use String.prototype.repeat();
Defer your script or place it right before the closing </body> tag
Learn the difference between let and const
function stars() {
const num = parseInt(document.getElementById('number').value, 10);
if (num < 2 || num > 10) return console.log("Use from 2 to 10 inclusive");
const row = '*'.repeat(num);
console.log(row)
}
document.getElementById("button").addEventListener('click', stars);
Give a number betweeen 2 and 10
<input type="number" id='number'>
<button id="button">Click</button>
i have called a counter function in loop. there are 4 items per page.
i have passed $i in loop and written 4 functions
but if i changed pagination limit to 5 or 10 ,it is not a good solution
anybody can help me to solve it?
here is my div in foreach loop where l called function
<div class="tick"
data-value="'.$start.'"
data-did-init="handleTickInit'.$i.'">
<div data-layout="horizontal center"
data-repeat="true"
">
<div data-view="swap"
></div>
</div>
handleTickInit'.$i is function
function handleTickInit2(tick) {
var value = tick.value;
var target = 0;
var timer = Tick.helper.interval(function() {
// have we reached the donation target yet?
if (value>=target) {
// no, keep going
var realprice=$("#realprice-2").val();
var startdate=$("#startdate-2").val();
var currenttime = Math.round((new Date()).getTime()/1000);
var stepsec=$("#stepsec-2").val();
// alert(stepsec);
var diffsec=currenttime-startdate;
var loss=diffsec*stepsec;
var start=realprice-loss;
tick.value = start.toFixed(4);
$("#saveval-2").val(start);
// value= tick.value ;
}
else {
// yes, stop the timer
timer.stop();
}
}, 1000);
}
please give some solution to make it dynamic
Try this
var handleTickInit = {};
var num = 5;
var handleFunc = function() {
return function (tick) {
var value = tick.value;
var target = 0;
var timer = Tick.helper.interval(function() {
// have we reached the donation target yet?
if (value>=target) {
// no, keep going
var realprice=$("#realprice-2").val();
var startdate=$("#startdate-2").val();
var currenttime = Math.round((new Date()).getTime()/1000);
var stepsec=$("#stepsec-2").val();
// alert(stepsec);
var diffsec=currenttime-startdate;
var loss=diffsec*stepsec;
var start=realprice-loss;
tick.value = start.toFixed(4);
$("#saveval-2").val(start);
// value= tick.value ;
}
else {
// yes, stop the timer
timer.stop();
}
}, 1000);
}
}
for(var i = 0; i< num; i++){
handleTickInit[i] = handleFunc();
}
console.log(handleTickInit);
All your handle tick functions are in handleTickInit;
the problem: after clicking a checkbox I change the cursor to "wait", but only after about 6 seconds the wait-cursor is to see. How to avoid this 6 sec pause ?
many thanks in advance
Wicki
code edited !
<html>
<head>
<title>Cursor-Test</title>
<script type="text/javascript">
var k = 0;
var t1 = 0;
var t2 = 0;
function cursor_wait() {
document.body.style.cursor = 'wait';
t1 = (new Date()).getTime();
k = k+1;
}
function cursor_clear() {
document.body.style.cursor = 'default';
}
function st() {
setTimeout(calc,500); //wait a bit
}
//long time action
function calc() {
ta = (new Date()).getTime();
var dummy = 0;
k = k+1;
for (var i=0; i<1000000;i++) {
for (var z=0; z<2000;z++) {
dummy = dummy + z + i;
}
}
tb = (new Date()).getTime();
tr = tb-ta;
cursor_clear();
t2 = (new Date()).getTime();
alert("nach clear, k="+k+" all time:"+(t2-t1)+" computing time:"+tr);
}
</script>
</head>
<body>
<h2>Cursor ändern: standard->wait->länger dauernde Aktion->standard</h2>
<div>wait-cursor erst nach ca. 6 sec</div>
<form name="some_form" action="index.php" method="get">
<input type="checkbox" name="nameless" value="5"
onMouseDown="cursor_wait()" onMouseUp="st()" /> Five
</form>
</body>
</html>
First off, setting c to the cursor style won't do you any good. Even if c were defined, it would be a string. Changing c's value would just make it point to a different string, not change the cursor's style. You may want to do this:
var c = document.body.style;
var t1 = 0;
var t2 = 0;
function cursor_wait() {
c.cursor = 'wait';
t1 = (new Date()).getTime();
k = k+1;
}
function cursor_clear() {
c.cursor = 'default';
}
//long time action
function calc() {
setTimeout(cursor_clear, 6000);
}
I removed other code to make it easier to see what you can do if you wanted to clear the cursor after 6 seconds and not block the UI.
Please Look at the following code only the last image moves.
http://jsfiddle.net/u8Bg3/
But second one works
http://jsfiddle.net/u8Bg3/1/
As pointed by the Er144 even this works with jquery
http://jsfiddle.net/u8Bg3/14/
I also found out appendchild works but not innerhtml
The difference between two is that in first one html exits in second one it's dynamically created
HTML
<body>
<div class="racetrack" id="racetrack"></div>
<div id="track-tmpl" class="hide">
<div class="track"><div id="player{{ x }}" class="runner"></div></div>
</div>
</body>
JS
var position = [0,40,80,120,80],
racetrack = document.getElementById('racetrack');
track_tmpl = document.getElementById('track-tmpl').innerHTML;
function Players(ele, ptimeout)
{
this.el = ele;
this.i = 0;
this.iterations = 0;
this.stop = 0;
this.timeout = ptimeout;
this.position = 0;
this.animate = function(){
if(this.i !== 0){
this.move((this.position + 5), this.i);
}
if(!this.stop){
if(this.i < 5){
setTimeout(function(_this){
_this.i++;
_this.animate();
},this.timeout,this);
}
if(this.i==5){
this.iterations ++;
if(this.iterations < 50){
this.i = 0;
this.animate();
}
else{
this.el.style.backgroundPosition = '120px 0px';
}
}
}
};
this.start = function(){
this.stop = 0;
this.animate();
};
this.move = function(to,positionIndex){
this.position = to;
this.el.style.backgroundPosition = '-'+position[positionIndex]+'px 0px';
this.el.style.webkitTransform = 'translate('+to+'px)';
this.el.style.mozTransform = 'translate('+to+'px)';
}
}
function Game(noOfPlayers){
this.noOfPlayers = noOfPlayers;
this.players = new Array();
for (var i = 0; i < this.noOfPlayers ; i++){
racetrack.innerHTML = racetrack.innerHTML + track_tmpl.replace('{{ x }}', i);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
/* issue here with dynamic added content*/
}
this.start = function(){
for (var i = 0; i < this.noOfPlayers; i++){
this.players[i].start();
}
};
}
var game = new Game(3);
game.start();
Why is that in dynamically added html only the last one moves
The issue is with creating the player(n) object inside the for loop along with the assignments to innerHTML using `+='. The modified fiddle: http://jsfiddle.net/u8Bg3/15/ works fine. Cheers for a good question!
var finalized_tracks= "" ;
for (var i = 0; i < this.noOfPlayers ; i++){
finalized_tracks += track_tmpl.replace('{{ x }}', i);
}
racetrack.innerHTML = racetrack.innerHTML + finalized_tracks;
for (var i = 0; i < this.noOfPlayers ; i++){
this.players.push(new Players(document.getElementById('player'+ i),(120+i)));
}
If you use the jquery:
var element = track_tmpl.replace('{{ x }}', i);
$(racetrack).append(element);
instead of the line where you change the innerHtml of racetrack div, all elements are moving.
However, I'm not sure, why...
theCoder has pretty much nailed the issue with your code there.
Just as an additional thought, you could manually build the necessary divs using javascript instead, it's more long winded however...
for (var i = 0; i < this.noOfPlayers ; i++){
var newTrack = document.createElement("div");
newTrack.id = "track"+i;
newTrack.className = "track";
var newPlayer = document.createElement("div");
newPlayer.id = "player"+i;
newPlayer.className = "runner";
newTrack.appendChild(newPlayer);
racetrack.appendChild(newTrack);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
}
The code below appends numbers in sequence from 1 to 10 when the start button is clicked. I'd like to use clearTimeout to cancel the operation when the stop button is clicked.
It seems to me that a dynamic variable must be created (where x is currently assigned the doSetTimeout function), but I have not yet found a way to do so. Any suggestions?
Thanks!
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
function doSetTimeout(func, func_param, time) {
setTimeout(function(){func(func_param);}, time);
}
function createNode(base) {
var node = document.createElement("p");
var writeI = base + "";
var textnode = document.createTextNode(writeI);
node.appendChild(textnode);
document.body.appendChild(node);
}
$(document).ready(function() {
$("#start").click(function() {
for (var i = 1; i <= 10; i++) {
var time = i*1000;
var x = doSetTimeout(createNode, i, time);
}
});
});
</script>
</head>
<body>
<button id="start">Start</button>
<button id="stop">Stop</button>
</body>
Get the return value of setTimeout, keep it in a list, and clear it when you click stop.
function doSetTimeout(func, func_param, time) {
return setTimeout(function(){func(func_param);}, time);
}
$(document).ready(function() {
var timeouts = [];
$("#start").click(function() {
for (var i = 1; i <= 10; i++) {
var time = i*1000;
timeouts.push(doSetTimeout(createNode, i, time));
}
});
$("#stop").click(function () {
for (var i = 0; i <= timeouts.length; i += 1) {
clearTimeout(timeouts[i]);
}
});
});
This might also clear timeouts that have already finished, but I doubt that's really very important.