I am working on a game that includes a knockout tournament, each player are positioned randomly and I'm trying to give a random score to the non-human players that will be displayed next to their name.
But I find myself with the following error:
Cannot set properties of null (setting 'innerHTML')
window.onload = function() {
players = ['John Cena', 'Pikachu', 'Ronaldo', 'Spiderman', 'Sonic Hedghehog', 'Ben 10', 'Mike Tyson', 'Goku'];
for (i = 1; i <= 8; i ) {
var x = Math.floor(Math.random() * players.length);
//create variables p1 to p8
window['p' i] = players[x];
//create variables p1_score to p8_score
window['p' i '_score'] = 0;
players.splice(x, 1);
}
document.getElementById('player1').innerHTML = p1;
document.getElementById('player2').innerHTML = p2;
document.getElementById('player3').innerHTML = p3;
document.getElementById('player4').innerHTML = p4;
document.getElementById('player5').innerHTML = p5;
document.getElementById('player6').innerHTML = p6;
document.getElementById('player7').innerHTML = p7;
document.getElementById('player8').innerHTML = p8;
while (p1_score < 5 && p2_score < 5) {
if (Math.random() >= 0.5) {
p1_score = Math.floor(Math.random() * 6) 0.5;
} else {
p1_score = Math.floor(Math.random() * 6);
}
if (Math.random() >= 0.5) {
p2_score = Math.floor(Math.random() * 6) 0.5;
} else {
p2_score = Math.floor(Math.random() * 6);
}
}
document.getElementById('player1_score').innerHTML = p1_score;
document.getElementById('player2_score').innerHTML = p2_score;
}
main {
display: flex;
flex-direction: row;
}
.round {
display: flex;
flex-direction: column;
justify-content: center;
width: 200px;
list-style: none;
padding: 0;
}
.round .spacer {
flex-grow: 1;
}
.round .spacer:first-child,
.round .spacer:last-child {
flex-grow: .5;
}
.round .game-spacer {
flex-grow: 1;
}
/*
* General Styles
*/
body {
font-family: sans-serif;
font-size: small;
padding: 10px;
line-height: 1.4em;
}
li.game {
padding-left: 20px;
}
li.game.winner {
font-weight: bold;
}
li.game span {
float: right;
margin-right: 5px;
}
li.game-top {
border-bottom: 1px solid #aaa;
}
li.game-spacer {
border-right: 1px solid #aaa;
min-height: 40px;
}
li.game-bottom {
border-top: 1px solid #aaa;
}
<h1>Knockout Tournament</h1>
<main id="tournament">
<ul >
<li > </li>
<li id="player1" ><span id="player1_score"></span></li>
<li > </li>
<li id="player2" ><span id="player2_score"></span></li>
<li > </li>
<li id="player3" ><span id="player3_score"></span></li>
<li > </li>
<li id="player4" ><span id="player4_score"></span></li>
<li > </li>
<li id="player5" ><span id="player5_score"></span></li>
<li > </li>
<li id="player6" ><span id="player6_score"></span></li>
<li > </li>
<li id="player7" ><span id="player7_score"></span></li>
<li > </li>
<li id="player8" ><span id="player8_score"></span></li>
<li > </li>
</ul>
<ul >
<li > </li>
<li ><span></span></li>
<li > </li>
<li ><span></span></li>
<li > </li>
<li ><span></span></li>
<li > </li>
<li ><span></span></li>
<li > </li>
</ul>
<ul >
<li > </li>
<li ><span></span></li>
<li > </li>
<li ><span></span></li>
<li > </li>
</ul>
</main>
I tested the random score feature with the first 2 players, a score was supposed to display next to their name. The error points to these two lines below:
document.getElementById('player1_score').innerHTML = p1_score;
document.getElementById('player2_score').innerHTML = p2_score;
I did search for posts about this specific error, and saw on other posts that usually the cause of this error is that the script didn't load before the page (body), so I tried the following solutions:
- Use window.onload to ensure the script loads first
- Move the script to the end of body
- Use setTimeout method
- Set script type to 'module'
None of the above solutions worked. Help will be appreciated, thanks in advance.
CodePudding user response:
The issue is caused by:
document.getElementById('player1').innerHTML = p1;
Since the player1_score
is inside that player1
's <li>
, you're removing it's child (the <span>
) by setting innerHTML
.
Now, since it's gone, getElementById
wont find it and throws an error.
I'd recommend using a separate <span>
to add the name so you won't have to deal with overwriting elements. Change the structure to something like:
<li id="player1" >
<span id="player1_name"></span>
<span id="player1_score"></span>
</li>
Edited demo, just the first player to show what I'm meaning:
window.onload = function() {
players = ['John Cena', 'Pikachu', 'Ronaldo', 'Spiderman', 'Sonic Hedghehog', 'Ben 10', 'Mike Tyson', 'Goku'];
for (i = 1; i <= 8; i ) {
var x = Math.floor(Math.random() * players.length);
//create variables p1 to p8
window['p' i] = players[x];
//create variables p1_score to p8_score
window['p' i '_score'] = 0;
players.splice(x, 1);
}
document.getElementById('player1_name').innerHTML = p1;
while (p1_score < 5 && p2_score < 5) {
if (Math.random() >= 0.5) {
p1_score = Math.floor(Math.random() * 6) 0.5;
} else {
p1_score = Math.floor(Math.random() * 6);
}
if (Math.random() >= 0.5) {
p2_score = Math.floor(Math.random() * 6) 0.5;
} else {
p2_score = Math.floor(Math.random() * 6);
}
}
document.getElementById('player1_score').innerHTML = p1_score;
}
main{display:flex; flex-direction:row; }
.round{display:flex; flex-direction:column; justify-content:center; width:200px; list-style:none; padding:0; }
.round .spacer{ flex-grow:1; }
.round .spacer:first-child,
.round .spacer:last-child{ flex-grow:.5; }
.round .game-spacer{flex-grow:1;}
body{font-family:sans-serif; font-size:small; padding:10px; line-height:1.4em; }
li.game{padding-left:20px; }
li.game.winner{font-weight:bold; }
li.game span{float:right; margin-right:5px; }
li.game-top{ border-bottom:1px solid #aaa; }
li.game-spacer{border-right:1px solid #aaa; min-height:40px; }
li.game-bottom{border-top:1px solid #aaa; }
<h1>Knockout Tournament</h1>
<main id="tournament">
<ul >
<li > </li>
<li id="player1" >
<span id="player1_name"></span>
<span id="player1_score"></span>
</li>
<li > </li>
</ul>
</main>