Reputation: 1149
I am trying to create a simple NodeJS leaderboard, and I'm using socket.io for the real-time connection between client and server. Everything goes fine, but upon pressing the Increase button, the page crashes and I have to close it. I can't see any errors in the browser console before the page crashes, and there are no errors in Command Prompt either, which is where I'm running the application from.
What I'm trying to achieve with the socket.on('increase')
is to work out whether the name given as the parameter is already in the table or not. If it is, then replace the score value in the other column of the table, but if it's not, then add a new row to the table with the username and score in it.
I don't know why the page is crashing, though. However, I am pretty sure that it's to do with the usernameForm
, as when I removed it, the problem no longer occurs.
index.html
<!doctype html>
<html>
<body>
<form id="usernameForm">
<input type="text" id="usernameFormInput" name="usernameFormInput">
<input type="submit" value="Submit">
</form>
<div id="users"></div>
<button id="increase">Increase</button><br>
<span id="score">0</span><br>
<table id="leaderboard">
<tr>
<th>Name</th>
<th>Score</th>
</tr>
</table>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var playerName = "Jeff";
var playerScore = 0;
document.getElementById("increase").onclick = function() {
playerScore += 1;
document.getElementById("score").innerHTML = playerScore;
socket.emit('increase', playerName, playerScore);
};
document.getElementById("usernameForm").onsubmit = function(e) {
var newUsername = document.getElementById("usernameFormInput").value;
socket.emit('newUser', newUsername);
console.log("new user client");
e.preventDefault();
}
socket.on('increase', function(user, score) {
for (i = 0; i < document.getElementById("leaderboard").rows.length; i++) {
if (document.getElementById("leaderboard").rows[i].cells[0].innerHTML == user) {
document.getElementById("leaderboard").rows[i].cells[1].innerHTML = score;
}
else {
var table = document.getElementById("leaderboard");
var row = table.insertRow(0);
var userCell = row.insertCell(0);
var scoreCell = row.insertCell(0);
userCell.innerHTML = user;
scoreCell.innerHTML = score;
}
}
});
socket.on('newUser', function(name) {
playerName = name;
console.log("new user client cb");
});
socket.on('updateUsers', function(usernames) {
document.getElementById('users').innerHTML = Object.values(usernames);
});
</script>
</body>
</html>
app.js
var io = require('socket.io')(http);
var usernames = [];
var userScore = {};
var isUsernameTaken = function(data) {
for (var i = 0; i <= Object.keys(usernames).length; i++) {
console.log("loop entered");
if(data == usernames[i]) {
console.log("Username '" + data + "' is taken.")
return true;
} else {
console.log("Username '" + data + "' is not taken.");
usernames.push(data);
updateUsers();
return false;
}
}
}
var updateUsers = function() {
io.emit('updateUsers', usernames);
console.log(usernames);
};
io.on('connection', function(socket) {
socket.on('increase', function(user, score) {
userScore[user] = score;
io.emit('increase', user, score);
});
socket.on('newUser', function(name) {
console.log("new user server");
if ( isUsernameTaken(name) ) {
console.log("username taken");
}
else {
console.log("new user server loop");
usernames.push(name);
io.emit('newUser', name);
}
});
});
http.listen(4000, function(){
console.log('listening on *:4000');
});
My apologies for the long-looking code, but while I am trying to maintain a MCVE, I also need to include all the associated code to get to the root of the problem.
Upvotes: 0
Views: 516
Reputation: 11
Your problem is on .insertRow, You have to use the size of the table length.
Here is a possible solution:
socket.on('increase', function (user, score) {
var len = document.getElementById("leaderboard").rows.length;
for (i = 0; i < len; i++) {
if (document.getElementById("leaderboard").rows[i].cells[0].innerHTML === user) {
return document.getElementById("leaderboard").rows[i].cells[1].innerHTML = score;
}
}
var table = document.getElementById("leaderboard");
var row = table.insertRow(len);
var userCell = row.insertCell(0);
var scoreCell = row.insertCell(1);
userCell.innerHTML = user;
scoreCell.innerHTML = score;
});
I've also made a few changes to the code since it was duplicating rows
Upvotes: 1
Reputation: 3247
event emitters are synchronous. It looks like .emit('increase'
is triggering the socket.on('increase'
synchronously and therefore creating an infinite loop which crashes webpages. Try doing socket.once
if it is supported, or otherwise removing the socket.on('increase'
event listener once it is fired the first time, if that fixes the page then you know that's the cause.
Upvotes: 1