Reputation: 397
I'm attempting to make a scoreboard in HTML, where a javascript function can change the scores for various players. However, the scores for all but one of the players don't display correctly.
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="scoreboard"></div>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Javascript:
function Player(ID) {
this.ID = ID;
var scoreboard = document.getElementById("scoreboard");
//Create a <p> in scoreboard with "Player n:" in it, and then
//create a <span> with the score and a unique ID to use for getting and setting
scoreboard.innerHTML += "<p>Player " + this.ID + ":" + "<span id=\"PlayerScore" + this.ID + "\">0</span></p>";
this.scoreElement = document.getElementById("PlayerScore" + this.ID); //set score element
//Getter and setter for score
this.getScore = function() {return Number(this.scoreElement.innerHTML);}
this.setScore = function(scoreIn) {this.scoreElement.innerHTML = scoreIn.toString();}
}
I test this code using the following Javascript:
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
player1.setScore(player1.getScore() + 1);
player2.setScore(player2.getScore() + 1);
player3.setScore(player3.getScore() + 1);
After doing this, the scoreboard in the generated webpage reads:
Player 1:0
Player 2:0
Player 3:1
However, it should read
Player 1:1
Player 2:1
Player 3:1
Any ideas? Why does only the last one work? Is it a problem with how I'm getting and setting directly from and to the InnerHTML of the scoreElement? Does it have anything to do with my browser (firefox)?
Upvotes: 2
Views: 3552
Reputation: 388446
The problem is your use of innerHTML
to append more content, once you use innerHTML +=
it will recreate all the dom elements so your scoreElement
references you created previously will no longer present in the dom tree that is why those are not getting updated.
The way to solve it is not to use .innerHTML
to append content, instead you can create dom elements and call the appendChild() method to add it to the parent element like
function Player(ID) {
this.ID = ID;
var scoreboard = document.getElementById("scoreboard");
var playerElement = document.createElement('p');
this.scoreElement = document.createElement('span');
this.scoreElement.innerHTML = 0;
playerElement.appendChild(document.createTextNode("Player " + this.ID + ":"));
playerElement.appendChild(this.scoreElement);
scoreboard.appendChild(playerElement)
//Getter and setter for score
this.getScore = function() {
return Number(this.scoreElement.innerHTML);
}
this.setScore = function(scoreIn) {
this.scoreElement.innerHTML = scoreIn.toString();
}
}
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
player1.setScore(player1.getScore() + 1);
player2.setScore(player2.getScore() + 1);
player3.setScore(player3.getScore() + 1);
<div id="scoreboard"></div>
As @dandavis said in the comments, another tweak you can do is
function Player(ID) {
this.ID = ID;
var scoreboard = document.getElementById("scoreboard");
var playerElement = document.createElement('p');
playerElement.innerHTML = "Player " + this.ID + ":" + '<span>0</span>';
this.scoreElement = playerElement.querySelector('span');
scoreboard.appendChild(playerElement)
//Getter and setter for score
this.getScore = function() {
return Number(this.scoreElement.innerHTML);
}
this.setScore = function(scoreIn) {
this.scoreElement.innerHTML = scoreIn.toString();
}
}
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
player1.setScore(player1.getScore() + 1);
player2.setScore(player2.getScore() + 1);
player3.setScore(player3.getScore() + 1);
<div id="scoreboard"></div>
Upvotes: 10
Reputation: 3084
the problem, every time you call the constructor, it rebuilds scoreboard.innerHTML
, meaning all its child elements are deleted and rebuilt,
so only in your last instance, this.scoreElement
dose not get rebuilt.
you could solve this either using appendChild or by getElementById
every time you get or set the score
function Player(ID) {
this.ID = ID;
var scoreboard = document.getElementById("scoreboard");
//Create a <p> in scoreboard with "Player n:" in it, and then
//create a <span> with the score and a unique ID to use for getting and setting
scoreboard.innerHTML += "<p>Player " + this.ID + ":" + "<span id=\"PlayerScore" + this.ID + "\">0</span></p>";
//Getter and setter for score
this.getScore = function() {return Number(document.getElementById("PlayerScore" + this.ID).innerHTML);}
this.setScore = function(scoreIn) { document.getElementById("PlayerScore" + this.ID).innerHTML = scoreIn.toString();}
}
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
player1.setScore(player1.getScore() + 1);
player2.setScore(player2.getScore() + 1);
player3.setScore(player3.getScore() + 1);
<div id="scoreboard"></div>
Upvotes: 2