Joenel de Asis
Joenel de Asis

Reputation: 363

Node.js & Socket.io Adding Username

I'm new to socket.io I would like to know how do i add username in this simple chat using socket.io. Thanks in advance guys. I would like to learn socket programming.

The code below is my server.js

//chat service
io.sockets.on('connection', function (socket) {
    socket.on('sendMessage', function (data) {
    socket.broadcast.emit('message', data);
    socket.emit('message', { text: data.text });   
    });   
});

This is my chat client index.html

<!-- index.html -->
<html> 
  <body>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script>
      $(document).ready(function () {
        var socket = io.connect('http://localhost');
        socket.on('message', function (data) {

          $('#chat').append( '<b>' + data.text + '</b>' + '<br />');

        });
            $('#send').click(function () {
            socket.emit('sendMessage', { text: $('#text').val() });
            $('#text').val('');
        });

            $('#text').keypress(function(event) {
              if(event.keyCode == 13) {
                $('#send').click();
                $('#text').val('');
              }
            });

      });
    </script>

    <div id="chat" style="width: 500px; height: 300px; border: 1px solid black">

    </div>    

    <input type="text" name="text" id="text">
    <input type="button" name="send" id="send" value="send">
  </body>
</html>

Upvotes: 6

Views: 27376

Answers (2)

ggorlen
ggorlen

Reputation: 57155

To add usernames to messages most simply, add the username to the messages from client to server:

Client:

socket.emit("chat message", {username, message});
socket.on("chat message", ({username, message}) => {
  console.log(username, message);
});

Server:

io.on("connection", socket => {
  socket.on("chat message", data => {
    // send to all clients but the sender
    socket.broadcast.emit("chat message", data);
  });
});

If you want to "register" a username once, you can keep a variable in each io.on("connection" ... closure in the server code, then use a "register username" message to let the client communicate their username (or assign one for them on the server, or optionally negotiate a valid username with a series of messages):

server.js:

const express = require("express"); // "^4.17.2"
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io")(server); // "^4.4.1"

app.use(express.static("public"));

io.on("connection", socket => {
  let username = "anonymous";

  socket.on("chat message", message => {
    io.emit("chat message", {username, message});
  });
  
  socket.on("register username", newUsername => {
    username = newUsername;
  });
});

server.listen(3000, () => console.log("server listening on port 3000"));

public/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.js"></script>
</head>
<body>
  <ul id="messages"></ul>
  <form id="message-form">
    <input autocomplete="off" />
    <input type="submit" value="send">
  </form>
<script>
const randomStr = (n=10) => [...Array(n)]
  .map(e => String.fromCharCode(~~(Math.random() * 26) + 97))
  .join("")
;
const username = prompt("what's your nickname?") || randomStr();
const socket = io.connect();
const messagesContainer = document.querySelector("#messages");

socket.on("connect", () => {
  socket.emit("register username", username);
});

socket.on("chat message", ({username, message}) => {
  const li = document.createElement("li");
  li.textContent = `[${username}] ${message}`;
  messagesContainer.appendChild(li);
});

document.querySelector("#message-form")
  .addEventListener("submit", e => {
    e.preventDefault();
   
    if (e.target.elements[0].value) {
      socket.emit("chat message", e.target.elements[0].value);
      e.target.reset();
    }
  })
;
</script>
</body>
</html>

For apps that need access to all active users from every socket closure, you can add the usernames to an object in a shared scope.

Here's a minimal proof of concept of using an object with the mapping socket.id => username:

public/index.html:

(mostly the same as above with the following additions)

<!-- ... -->
<h3>current users:</h3>
<ul id="users"></ul>
<!-- ... -->

<script>
// ...
const usersEl = document.querySelector("#users");
socket.on("users", ({users}) => {
  usersEl.innerHTML = "";

  for (const user of users) {
    const li = document.createElement("li");
    li.textContent = user;
    usersEl.appendChild(li);
  }
});
// ...
</script>
<!-- ... -->

server.js:

// ...
const usersBySocketId = {};

io.on("connection", socket => {
  socket.on("disconnect", () => {
    delete usersBySocketId[socket.id];
    io.emit("users", {users: Object.values(usersBySocketId)});
  });

  socket.on("chat message", message => {
    io.emit("chat message", {username: usersBySocketId[socket.id], message});
  });

  socket.on("register username", username => {
    usersBySocketId[socket.id] = username;
    io.emit("users", {users: Object.values(usersBySocketId)});
  });
});
// ...

In a more complex app, there's usually additional data you want to store on the object. Sometimes a reverse mapping of usernamme => socket.id is useful too.

I haven't validated username uniqueness or other properties, but that's another typical requirement that adds some complexity.

Upvotes: 2

Tamas
Tamas

Reputation: 11214

Have a look here - http://www.tamas.io/2013/05/19/simple-chat-application-using-node-js-and-socket-io/

The easiest way is to add a people's object - see the source code (link in the article).

If you want to implement rooms as well, read this: http://www.tamas.io/2013/05/19/simple-chat-application-using-node-js-and-socket-io/

Have fun.

Upvotes: 5

Related Questions