I have the following code that runs a loop and updates the page as it goes. At the moment the page does not update until the entire loop has run its course.
As you can see, I tried adding a draw function drawValues that is called every 5000 times to draw the current values to the screen. My understanding is that when drawValues is updated, the page should update and then the main loop will resume with its calculations until another 5000 loops.
At the moment the page will not update until the loop runs in its entirety, somehow ignoring every other call to drawValues
Full Snippet:
/*jslint browser: true*/
/*global $, jQuery, alert*/
$(document).ready(function() {
'use strict';
var namesAtStart = ["Sam", "John"],
specialNum = 8,
amountOfNames = namesAtStart.length,
counter = [],
renderCounter = 0,
x,
a,
loopLength,
number,
id,
preId = "content_",
finalId;
for (a = 0; a < amountOfNames; a += 1) {
counter.push(0);
}
for (x = 1; x <= specialNum; x += 1) {
// Start the counter array at zero
for (a = 0; a < amountOfNames; a += 1) {
counter[a] = 0;
}
loopLength = Math.pow(10, x);
finalId = preId + loopLength.toString();
$(".output-small").append('<span id="' + finalId + '"></span>');
for (a = 0; a < loopLength; a += 1) {
number = Math.floor((Math.random() * amountOfNames) + 1);
counter[number - 1] += 1;
renderCounter += 1;
if (renderCounter == 5000) {
drawValues(namesAtStart, counter, finalId, x, a);
}
if (a == loopLength - 1) {
// This is where I am trying to make the code non blocking and async
drawValues(namesAtStart, counter, finalId, x, a);
}
}
}
});
// This is the part that I want to run when called and update page.
function drawValues(names, counter, finalId, id, currentCount) {
'use strict';
var a;
$("#" + finalId).empty();
$("#" + finalId).append("<h3>" + Math.pow(10, id).toLocaleString() + "</h1>");
for (a = 0; a < names.length; a += 1) {
$("#" + finalId).append(
names[a] + ": " + counter[a].toLocaleString() + " (" + (counter[a] / currentCount * 100).toFixed(2) + "%)</br>"
);
}
$("#" + finalId).append("Numerical Difference: " + Math.abs(counter[0] - counter[1]) + "</br>");
$("#" + finalId).append(
"Percentage Difference: " + Math.abs(
(counter[0] / currentCount * 100) - (counter[1] / currentCount * 100)
).toFixed(6) + "%</br>"
);
$("#" + finalId).append("</br>");
}
body {} p,
h3 {
padding: 0px;
margin: 0px;
}
.container {} .output {} .output-small {
margin: 20px;
padding: 5px;
border: 1px solid rgba(0, 0, 0, 1);
width: 300px;
border-radius: 10px;
}
#stats-listing {}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<title>Roll The Dice</title>
<body>
<div class="container">
<div class="output" id="stats-listing">
<div class="output-small"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="logic.js"></script>
</body>
</html>
The main UI thread in browsers, which is used to run JavaScript, is single-threaded. So if you have a function that's taking a lot of time, the browser doesn't update the display.
To give the browser a chance to update the display, you need to yield back to it by letting your current function end and scheduling a timed callback to another run of it for the next block of updates, via setTimeout. You'll have to experiment with the browsers you want to support to determine the delay in the timed callback; some browsers are happy with 0 (call back as soon as possible), others want longer (50 — 50 milliseconds — is plenty for every browser I know).
Here's a simple example that adds 10 boxes to the page, yields, then adds another 10, yields, etc. until it's done 1,000 boxes:
(function() {
var total = 0;
addBoxes();
function addBoxes() {
var n;
for (n = 0; n < 10 && total < 1000; ++n, ++total) {
box = document.createElement('div');
box.className = "box";
document.body.appendChild(box);
}
if (total < 1000) {
setTimeout(addBoxes, 10); // 10ms
}
}
})();
.box {
display: inline-block;
border: 1px solid green;
margin: 2px;
width: 20px;
height: 20px;
}
Related
how to make a stimulus (image, div, whichever's easiest) show up on right or left half of screen randomly using javascript.
Any ideas about having the button clicks record the reaction time, which button is clicked (left or right), and which side the stimulus was presented on?? Also, the left button should be "true" when stimulus is presented on the right and vice versa.
<head>
<style >
.divStyleLeft {
width: 300px;
height: 300px;
background-color: lightblue;
float: left;
}
.divStyleRight {
width: 300px;
height: 300px;
background-color: lightgreen;
float: right;
}
.maxWidth {
width: 100%;
}
.button {
float: right;
}
.button2 {
float: left;
}
</style>
</head>
<body onload="presentStimulus()">
<div class="button">
<button onclick="presentStimulus()">Click Me</button>
</div>
<div class="button2">
<button onclick="presentStimulus()">Click Me </button>
</div>
<div class="maxwidth"></div>
<div id="float" class="divStyleLeft" onclick="recordClick()">
I AM NOT FLOATING
</div>
<script>
let numClicks= 0;
let timeStart = 0;
let timeEnd = 0;
function Trial(trialTime, sidePresented,buttonClicked,) {
this.trialTime = trialTime;
this.sidePresented= sidePresented;
this.buttonClicked= buttonClicked;
}
let allTrials = [];
for(x = 0; x < 12; x++)
allTrials.push(new Trial(0,0,0));
Trial.prototype.toString=function(){
return this.trialTime + "ms, Side : " + this.sidePresented + ", Reaction Time: " + this.buttonClicked
+ "<br>";
};
function presentStimulus() {
const elem = document.querySelector ( '#float' );
const min = 1;
const max = 2;
const v = Math.floor(Math.random() * (max - min + 1)) + min;
console.log ( 'Random num is ' + v + ": ", '1 will go left, 2 will go right' );
v === 1 ?
( () => {
elem.classList = [ 'divStyleLeft' ];
elem.innerText = 'Hello!';
} ) () :
( () =>{
elem.classList = [ 'divStyleRight' ];
elem.innerText = 'Hi!';
} ) ();
}
function recordClick()
{
let theData = document.getElementById("#float").data;
timeEnd = Date.now();
allTrials[numClicks].trialTime = timeEnd - timeStart;
allTrials[numClicks].sidePresented = theData.sidePresented;
allTrials[numClicks].buttonClicked = theData.buttonClicked;
if (numClicks < 11) {
numClicks++;
presentStimulus();
}
else {
document.getElementById("float").style.visibility = "hidden";
let output = "";
for (x = 0; x < allTrials.length; x++)
output = output + "<b>:" + (x + 1) + "</b>:" + allTrials[x].toString();
document.getElementById("display").innerHTML = output;
}
}
</script>
<p id="display"></p>
</body>
There's a bunch of ways you could go about this.
If you're using plain 'ol JS, I'd probably create classes in CSS that float left or right, possibly appear as a flex container that displays left or right, whatever your specific need might be (again, there's a lot of ways to go about it, and one might be better than the other given your context).
When you've determined left or right (gen a random number or whatever), update the classlist on the DOM elements with the desired class to make it go this way or that.
For what it's worth, here's a bare-bones vanilla JS example. Again, I don't know your specific context, but this should give you a start on how to look at it. Floating may not be ideal, you may want to just hide/show containers that already exist on the left or right or actually create whole new DIVs and insert them into known "holder" containers (usually just empty divs), but the idea is the same; gen the random number, alter the classlists of the elements you want to hide/show/move/whatever, and if necessary, alter the innerHTML or text as needed.
<html>
<head>
<style>
.divStyleLeft {
width: 300px;
height: 300px;
background-color: lightblue;
float: left;
}
.divStyleRight {
width: 300px;
height: 300px;
background-color: lightgreen;
float: right;
}
.maxWidth {
width: 100%;
}
</style>
</head>
<body>
<button onclick="onClick()">Click Me</button>
<div class="maxwidth">
<div id="floater" class="divStyleLeft">
I AM NOT FLOATING
</div>
<div>
<script>
function onClick () {
const elem = document.querySelector ( '#floater' );
const min = 1;
const max = 2;
const v = Math.floor(Math.random() * (max - min + 1)) + min;
console.log ( 'Random num is ' + v + ": ", '1 will go left, 2 will go right' );
v === 1 ?
( () => {
elem.classList = [ 'divStyleLeft' ];
elem.innerText = 'I am floating LEFT';
} ) () :
( () =>{
elem.classList = [ 'divStyleRight' ];
elem.innerText = 'I am floating RIGHT';
} ) ();
}
</script>
</body>
</html>
Question: so im doing a timesheet and i have 3 inputs with start, end and break and would like to do a live calculate with it but it need to be with a : i have found some live calculator but non of them is time based and can take :
so the question how would i do it?
so this is what i got but it does not do time :
http://jsfiddle.net/5xzSy/1848/
Example: 08:00(start)10:00(end)01:00(break) and that would be 01:00(total)
so end-start-break=total
var start = $('#start'),
end = $('#end'),
brk = $('#break'),
total = $('#added'),
timespan;
$('input').keyup(function() { // run anytime the value changes
var e = toMins(end.val()),
s = toMins(start.val()),
b = toMins(brk.val());
if (!s || !e) return;
var output = (e - s - b) / 60;
total.html(Math.floor(output) + ':' + toDouble(Math.round((output % 1) * 60)));
});
function toMins(val) {
if (!val) return 0;
val = val.split(':');
return (Number(val[0]) * 60) + Number(val[1] || 0);
}
function toDouble(n) {
return n < 10 ? ('0' + n) : n;
}
table { margin: 10px; }
table td { padding: 2px 4px; }
input { width: 60px; padding: 2px 4px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr><td>Start:</td><td><input id=start placeholder="hh:mm"></td></tr>
<tr><td>End:</td><td><input id=end placeholder="hh:mm"></td></tr>
<tr><td>Break:</td><td><input id=break placeholder="hh:mm"></td></tr>
<tr><td>Total:</td><td><span id=added></span></td></tr>
</table>
I recommend you tu use a framework like Angular or VueJS that make that kind of requirements easier
https://vuejs.org/
https://angular.io/
I have tried to make the code works fine in stackoverflow but when I added the javascript code, it has stopped.any way
I have this code:
showCharacters("hey, how are you");
function showCharacters(text) {
var charactersArray = new String(text).split('');
var i;
for (i = 0; i < charactersArray.length; i++) {
setCharacter(i, charactersArray);
}
deleteAll(i - 1);
}
function setCharacter(i, charactersArray) {
setTimeout(function() {
document.getElementById("characters").innerHTML = document.getElementById("characters").innerHTML + charactersArray[i];
}, 1000 * i);
}
function deleteAll(i) {
setTimeout(function() {
var text = document.getElementById("characters").innerHTML;
var charactersArray = new String(text).split('');
var charactersArrayLength = charactersArray.length - 1;
for (var j = charactersArrayLength; j >= 0; j--) {
charactersArray.splice(j, 1);
deleteCharacter(charactersArray.join(""), i + charactersArrayLength - j + 1);
}
}, (i + 1) * 1000);
}
function deleteCharacter(text, i) {
setTimeout(function() {
document.getElementById("characters").innerHTML = text;
}, 1000 * i);
}
#divContainer {
display: flex;
align-items: center;
float: right;
}
#characters {
font-weight: 700;
color: rgb(0, 0, 0);
font-size: 40px;
padding-top: 2px;
white-space: nowrap;
}
<div id="divContainer">
<h1 id="characters">
</h1>
</div>
I made the code to write one character every second and after complete the text it will delete one character every second,the problem is that after complete the text it will wait for a few seconds before starting deleting the characters.I did not do that.
I have followed the time value of settimeout method and everything is fine.
I want it to start deleting characters directly after complete the text.
any help please.
Dont line up app the timeouts in a row do them one after the other.
Here is how you should do it. I speed the time up a bit, but that matters not.
var text = "Add a new timeout as needed."
var div = document.createElement("div");
document.body.appendChild(div);
var textPos = 0;
function textAdd(){
div.textContent += text[textPos++];
if(textPos >= text.length){
setTimeout(clearText,1000);
}else{
setTimeout(textAdd,200);
}
}
function clearText(){
textPos --;
div.textContent = text.substr(0,textPos);
if(textPos === 0){
setTimeout(textAdd,1000);
}else{
setTimeout(clearText,200);
}
}
textAdd();
I stayed close to your code, the fix was actually quite simple, I marked it with THE FIX below.
// Replace spaces with non-breaking spaces so it does not stutter, and use global var
var text = "hey, how are you".replace(/ /g, String.fromCharCode(160));
showCharacters();
function showCharacters() {
var chars = new String(text).split('');
var i;
for (i = 0; i < chars.length; i++) {
setCharacter(i, chars);
}
deleteAll(i - 1);
}
function setCharacter(i, chars) {
setTimeout(function() {
document.getElementById("characters").innerHTML = document.getElementById("characters").innerHTML + chars[i];
}, 200 * i);
}
function deleteAll(i) {
setTimeout(function() {
var chars = new String(text).split('');
var len = chars.length - 1;
for (var j = len; j >= 0; j--) {
chars.splice(j, 1);
deleteCharacter(chars.join(""), i - j + 1); // THE FIX: don't add length here
}
}, (i + 1) * 200);
}
function deleteCharacter(text, i) {
setTimeout(function() {
document.getElementById("characters").innerHTML = text;
}, 200 * i);
}
#divContainer {
display: flex;
align-items: center;
float: right;
}
#characters {
font-weight: 700;
color: rgb(0, 0, 0);
font-size: 40px;
padding-top: 2px;
white-space: nowrap;
}
<div id="divContainer">
<h1 id="characters">
</h1>
</div>
I am a guitar addict and I try to make a UI for guitar tablature.
In my js code, you can see
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8',
's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
's6f1' means string 6 & fret 1 and I want to show it on tablature. The way I show this is to put a "1" on string 6. Please the picture below. In my code, I basically traverse the notes array and attach each note on tablature . I define each 6 six lines as a group. After a group is filled with 4 notes, a new group is shown. Since In my real application, I do not know how many notes that notes array has(In this examples, I just simplify there are 15 notes), I have to dynamically create each group and assign each line a unique id. My question is that I do not know how to attach the number on the string. For instance, after dynamically create a "six-line", how do I attach the number on the correct line. I think the challenge in my question is that I cannot predefine the location of six-liner in html. The code below is the html, css, js code that I wrote. Hope someone could help me out. Thank you in advance.
html:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="code.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="code_js.js"></script>
</head>
<body>
</div>
<div id = "output">
</body>
</html>
css:
.deco {
border-bottom: 1px solid black;
width: 120px;
margin-left:0px;
margin-bottom:10px;
z-index: 2;
position: relative;
display: block;
margin-right: 20px;
}
#output {
width: 300px;
height: 200px;
position:absolute;
float:left;
background-color: yellow;
}
.six_line {
width: 125px;
height: 80px;
float:left;
margin-right: 20px;
}
js:
"use strict"
var count = 0;
var group = -1;
$(document).ready(function() {
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
hideNote(notes, 0);
});
function hideNote(notes, i) {
var x = -2;
if(count == 4) {count = 0;}
if(count++ == 0) {
group++;
makeItHappen();
}
var ns4 = notes[i];
// retrive the info of string
var ns2 = ns4.substring(0,2);
x = parseInt(ns4.substring(1,2)) + (group*6);
**/*How to attach fret(#) on the string*
// finds the line with corresponding id
$('#hr' + x).attr('class', '?');
*/**
hide(function(){
if(++i < notes.length) {
hideNote(notes, i);
}
},notes[i]);
}
function hide(callback, note) {
setTimeout(function(){
callback();
}, 1000);
}
function makeItHappen() {
var six = document.createElement('div');
six.className = "six_line";
for (var i = 1; i < 7; i++) {
var hr = document.createElement('hr');
hr.className = "deco";
hr.id = "hr" + (group * 6 + i);
six.append(hr);
}
$('#output').append(six);
}
I suggest some modifications in your code.
Starting with the function that creates your strings:
function makeItHappen(nbGroup) {
for(var g = 1; g <= nbGroup; g++){
var six = document.createElement('div');
six.className = "six_line";
for (var i = 6; i >= 1; i--) {
var string = document.createElement('div');
string.className = "deco";
string.id = "string" + ('G' + g + 'S' + i);
six.append(string);
}
$('#output').append(six);
}
}
That will create all your groups of strings at the same time. It becomes easily to attribute an explicit ID for each of them : strGiSj where i is the group and j the string in the group.
Next, how about the hideNode function:
function hideNote(notes) {
makeItHappen(Math.ceil(notes.length / 4));
notes.forEach(function(n, i){
var values = n.match(/s(\d)f(\d)/); // values[1] = string, values[2] = fret
var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
var child = $("<div></div>")
.addClass("fret")
.css("left", (10+ (i%4) * 25) + "px")
.text(values[2]);
parentEl.append(child)
});
}
We create the amount of groups needed (amount of notes / 4 rounded to next int). For each note in your array, we retrieve the string and the fret with a regular expression /s(\d)f(\d+)/:
\d matches a digit
\d+ matches one or more digits
Parenthesis allow to retrieve values easily
Next, we just have to retrieve the appropriate group, and retrieve the associated div with good id, then create the fret element and place it.
The full code looks like this:
"use strict"
$(document).ready(function() {
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
hideNote(notes);
});
function hideNote(notes) {
makeItHappen(Math.ceil(notes.length / 4))
notes.forEach(function(n, i){
var values = n.match(/s(\d)f(\d+)/);
var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
var child = $("<div></div>")
.addClass("fret")
.css("left", (10+ (i%4) * 25) + "px")
.text(values[2]);
parentEl.append(child)
})
}
function makeItHappen(nbGroup) {
for(var g = 1; g <= nbGroup; g++){
var six = document.createElement('div');
six.className = "six_line";
for (var i = 6; i >= 1; i--) {
var string = document.createElement('div');
string.className = "deco";
string.id = "string" + ('G' + g + 'S' + i);
six.append(string);
}
$('#output').append(six);
}
}
Here is a codepen with a working sample.
I'm making a small exercise for some students of mine where I am automating a kind of 10 pin bowling game I have put it into a JsBin here https://jsbin.com/qilizo/edit?html,js,output. I don't know whether I am tired, stupid or it's just because I am working on a national holiday but something has me puzzled. When i start the game I prompt the user to set up a number of desired players. This automatically produces an object array of Players like so:
[{score: Array[10], spareCount: 0, strikeCount: 0, username: "Player 1"}, ...]
Now later I allow the user to play frames where each Player in our array has two throws... I collect the score and add it to the certain player's score array. However when I try to perform this action using a .forEach method the score I generate is applied to all items in my Players array (play the game and see). I have put my code in a jsBin and the problem is on line 109 : a.score[currentFrame - 1] = playFrame();
I have tried to amend my code but I can't work out why the current (or last) frame score is being applied to all Player objects! If you can understand my syntax error and explain why I would be most appreciative. Play the game (just click the button after setting the player numbers) and you will see what I mean...
Snippet:
var players,
currentFrame = 0,
currentThrow = 0;
// helper functions
// Accurate isNumber function... Thank you Crockford (see JavaScript: The Good Parts)
function isNumber(value) {
return typeof(value === 'number') && isFinite(value);
}
function frameStyle(k) {
var returnCssClass,
k = k + 1;
if (k < currentFrame) {
returnCssClass = 'played-frame';
} else if (k === currentFrame) {
returnCssClass = 'current-frame';
} else {
returnCssClass = null;
}
return returnCssClass;
}
function setUpPlayers(num) {
var tempArray = [],
tempName = 'Player ',
emptyScores = Array(10).fill([-1, -1]); // set default to -1 as a rubbish player may hit no pins!
for (var i = 0; i < num; i++) {
tempArray.push({
username: tempName + (i + 1),
score: emptyScores,
strikeCount: 0,
spareCount: 0
}); // the way I have named the tempName is technically an antipattern!
}
return tempArray;
}
function getTotals(scores) {
var totalScore = scores.reduce(function(a, b) {
return a + b.reduce(function(c, d) {
return (c + (c + ((d > 0) ? d : 0)));
}, 0);
}, 0);
return totalScore;
}
function displayScore(score) {
// toDo reformat!
var formatScore = score.map(function(a, b) {
if (a === -1) {
a = '-';
} else if (a === 10) {
a = 'X';
}
return a;
});
return formatScore;
}
function createGrid() {
// If only I was using ES6 I could have multi line support!
var playerLen = players.length,
scoresLen = players[0].score.length;
boards = '<div class="score-board">' +
'<!-- one row for each player -->';
// need to loop this through the players...
for (var i = 0; i < playerLen; i++) {
boards += '<div class="row">' +
'<!-- first cell is the name -->' +
'<div class="name">' + players[i].username + '</div>';
// need to loop this with the users scores
for (var k = 0; k < scoresLen; k++) {
boards += '<div class="game ' + frameStyle(k) + ' ">' + displayScore(players[i].score[k]) + '</div>';
}
// don't forget the total
boards += '<div class="player-total">' + getTotals(players[i].score) + '</div>';
boards += '</div>';
}
boards += '</div>';
boards += '<div>Current Frame: ' + currentFrame + '</div>';
boards += '<button type="button" onclick="startGame()">Start Game</button>';
// fill the holder....
document.getElementById('boardHolder').innerHTML = boards;
}
function startGame() {
if (currentFrame >= 10) {
announceWinner();
} else {
currentFrame++;
// do the throws for Each Player!
players.forEach(function(a, b) {
a.score[currentFrame - 1] = playFrame();
});
// update the grid
createGrid();
// recurrrrrrsion....
//startGame();
}
}
function throwBall(pinsStanding) {
// i know it isn't a ball
return Math.floor(Math.random() * (pinsStanding + 1));
}
function playFrame() {
// here we just create the array and determine if we have a strike or a spare!
var pinsStanding = 10,
frameScore = [],
frameThrows = 2,
pinsDown;
for(var i = 0; i < frameThrows; i++) {
pinsDown = throwBall(pinsStanding);
pinsStanding = pinsStanding - pinsDown;
// if it is the pinsStanding = 0 and it is the first throw - a strike!
if(pinsStanding === 0 && i === 1) {
pinsStanding = 10;
frameThrows = 3;
}
// what if it is a spare?
frameScore.push(pinsDown);
}
return frameScore;
}
function announceWinner() {
}
// kick it all off!!!
window.onload = function() {
// lets get some users....
players = prompt('Please enter the NUMBER of players?', 2);
// check we have a number...
if (isNumber(players)) {
players = setUpPlayers(players);
createGrid();
}
};
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
/* classes */
.score-board {
border: 1px solid #000;
}
.row {
display: block;
border-bottom: 1px solid #000;
}
.row:last-child {
border-bottom: none;
}
.row > div {
display: inline-block;
padding: 5px;
}
.game {
border-right: 1px solid #000;
}
.name {
background-color: #f5f5f5;
border-right: 1px solid #000;
}
.player-total {
text-align: right;
background-color: #d5eabb;
}
.played-frame {
background-color: #aee1e8;
}
.current-frame {
background-color: #ffc0cb;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<h1>Let's go bowling!</h1>
<div id="boardHolder">
</div>
</body>
</html>
Here is the bin!
https://jsbin.com/qilizo/edit?html,js,output
You need to call Array(10).fill([-1, -1]) inside for loop, because otherwise all objects will share the same score array:
function setUpPlayers(num) {
var tempArray = [],
tempName = 'Player ';
for (var i = 0; i < num; i++) {
tempArray.push({
username: tempName + (i + 1),
score: Array(10).fill([-1, -1]),// set default to -1 as a rubbish player may hit no pins!
strikeCount: 0,
spareCount: 0
}); // the way I have named the tempName is technically an antipattern!
}
return tempArray;
}
https://jsbin.com/yeyupiteyu/1/edit?html,js,output
In JavaScript objects are passed by reference, and since array is an object, if you declare emptyScores outside the loop and then assign it to every element of the array, all elements will share the same score array.
You have make new emptyScores array for each element, so you have to declare it inside the loop:
var tempArray = [],
tempName = 'Player ';
for (var i = 0; i < num; i++) {
var emptyScores = Array(10).fill([-1, -1]);
tempArray.push({
username: tempName + (i + 1),
score: emptyScores,
strikeCount: 0,
spareCount: 0
});
}