Adding the user to the room is great, but if we can't target them specifically and others in that room, it's not very useful. Well it turns out we have a couple of ways to do just that. In order to illustrate how we're going to target specific users, let's look at all the ways we've emitted events on the server.
We've used io.emit. This emits it to every single connected user, and that's currently what we're doing for things like createMessage. A new message comes in and we emit it to everyone connected. Next up, we have used socket.broadcast.emit. We use that with newMessage and as we know this sends the message to everyone connected to the socket server except for the current user. The last one we used inside server.js is socket.emit. This emits an event specifically to one user. Now we can take these events and we can convert them over to their room counterpart. In order to send it to a specific room, we're going to be chaining on the to method.
This is going to look a little something like this. Let's say we want to emit an event to every single person connected to a room, and let's just call this room The Office Fans for the moment. To do that, we're going to call io.to. The .to is a method and it takes the room name exactly as it was provided in the call to join. In our case, that is going to be The Office Fans, just like this:
socket.join(params.room);
// socket.leave('The Office Fans');
// io.emit ->io.to('The Office Fans')
Then we would chain on a call to emit. This is going to send an event to everybody connected to a room, The Office Fans:
socket.join(params.room);
// socket.leave('The Office Fans');
// io.emit ->io.to('The Office Fans').emit
Now we can also do the same thing with broadcast, meaning that we want to send an event to everybody in a room except for the current user. In order to do that we would useĀ socket.broadcast.to. This works just like the to the method defined previously, The Office Fans would get passed in, and on here we would call emit:
socket.join(params.room);
// socket.leave('The Office Fans');
// io.emit ->io.to('The Office Fans').emit
// socket.broadcast.emit -> socket.broadcast.to('The Office Fans')
This is going to send an event to everybody in The Office Fans room except for the current user, the one who's actually calling socket.broadcast.
Now the last way we've used emit is socket.emit. We're still going to use that when we want to send something to a specific user. There is no reason to target them by rooms since we just want to target them:
socket.join(params.room);
// socket.leave('The Office Fans');
// io.emit ->io.to('The Office Fans').emit
// socket.broadcast.emit -> socket.broadcast.to('The Office Fans').emit
// socket.emit
This are the two ways we're going to emit to specific rooms. Now in order to actually start wiring some of that up what we can do is take the following two calls and we can move them down insideĀ join, meaning that we're not going to tell someone that someone joined a room until they've actually joined the room by calling join:
socket.emit('newMessage', generateMessage('Admin', 'Welcome to the chat app'));
socket.broadcast.emit('newMessage', generateMessage('Admin', 'New user joined'));
We're also not going to tell a user that they have joined a room until the call has actually gone through. It might not go through if the data, like the name or the room name, are invalid. Let's take both of these calls and cut them out, and we're just going to take them as they are and move them down into join. For the moment we can move them down below our comments; I'm going to leave the comments in place so you have these as a reference down the line. Now right below the socket.join line, we call socket.emit and we emit a new message, Welcome to the chat app:
socket.emit('newMessage', generateMessage('Admin', 'Welcome to the chat app'));
And this line it is actually going to stay the same, we still just want to target any specific user.
The next line is going to change though. Instead of broadcasting to every connected user, we're going to broadcast to just users inside the room we just joined, using socket.broadcast.to, passing in params.room. We're going to emit a new message and this is going to let everyone know that a new user has joined.
socket.broadcast.to(params.room).emit('newMessage', generateMessage('Admin', 'New user joined'`));
Instead of new user, we can actually specify the name. We have access to that. Right here, I'm going to use a template string injecting the name first, params.name, followed by has joined:
socket.broadcast.to(params.room).emit('newMessage', generateMessage('Admin', `${params.name} has joined.`));