Now that we have support for creating multiple rooms, let us go ahead and add a page to list, join, and create new rooms. We will begin by adding a Jade view named rooms.jade
with the following code:
extends layout block append head script(type='text/javascript', src='/socket.io/socket.io.js') script(type='text/javascript', src='/javascripts/rooms.js') block content section#chatrooms div#new_room span Start a new Room input#new_room_name(type="text") input#new_room_btn(type="button", value="Start") div#allrooms div#header Or join a room div#rooms_list
This view has an input box to accept a new room name and a div
tag to add the list of existing rooms. We are also adding scripts for socket.io.js
and a new script file for our client-side code for listing rooms, namely rooms.js
. Next, create the rooms.js
script file with the following code:
var chatInfra = io.connect('/chat_infra'), chatInfra.on("connect", function(){ chatInfra.emit("get_rooms", {}); chatInfra.on("rooms_list", function(rooms){ for(var room in rooms){ var roomDiv = '<div class="room_div"><span class="room_name">' + room + '</span><span class="room_users">[ ' + rooms[room] + ' Users ] </span>' + '<a class="room" href="/chatroom?room=' + room + '">Join</a></div>'; $('#rooms_list').append(roomDiv); } }); }); $(function(){ $('#new_room_btn').click(function(){ window.location = '/chatroom?room=' + $('#new_room_name').val(); }); });
In the preceding code, we are connecting based on the chat_infra
namespace, requesting the chat rooms on it, and rendering them in the view. Let us take a quick look at an important step happening here:
chatInfra.emit("get_rooms", {});
As shown in the preceding code, the first thing we do after connecting is emit an event to get_rooms
. This will request the list of rooms from the server. Next, we set a listener to receive the list of rooms and render them:
chatInfra.on("rooms_list", function(rooms){
In the handler, as shown in the following code block, we are looping over the map of rooms and number of users in them and appending it to the room list:
for(var room in rooms){ var roomDiv = '<div class="room_div"><span class="room_name">' + room + '</span><span class="room_users">[ ' + rooms[room] + ' Users ] </span>' + '<a class="room" href="/chatroom?room=' + room + '">Join</a></div>'; $('#rooms_list').append(roomDiv); }
Finally, we have the code to create a new room. To create a new room, all we need to do is redirect to the chat room, with the name for the new room in the URL parameters:
$('#new_room_btn').click(function(){ window.location = '/chatroom?room=' + $('#new_room_name').val(); });
Next, we need to add a get_rooms
handler on the server to return the list of the rooms. For this, we will add the handler on the chat_infra
namespace in sockets.js
:
this.chatInfra.on("connection", function (socket) { //EXISTING CODE socket.on("get_rooms", function(){ var rooms = {}; for(var room in io.sockets.manager.rooms){ if(room.indexOf("/chat_infra/") == 0){ var roomName = room.replace("/chat_infra/", ""); rooms[roomName] = io.sockets.manager rooms[room].length; } } socket.emit("rooms_list", rooms); }); });
We can get the list of all the rooms using io.sockets.manager
and then we can build the map expected by our client by looping over the list. In our case, we filter to get rooms only from chat_infra
as they will also be created in chat_com
, and we don't want duplicates. Once we have the map, we will emit it as rooms_list
. Following this we will need to add the entry to our routes/index.js
file, as shown here:
exports.rooms = function(req, res){ res.render('rooms', { title: 'Express Chat' }); }
We also need to add the mapping in app.js
to server rooms at /rooms
:
app.get('/rooms', routes.rooms);
Finally, let us add some CSS styling for our new room's page in style.css
:
#chatrooms{ margin: 20px; } #new_room { font-size: 17px; } #new_room span{ padding-right: 15px; } #allrooms #header{ border-bottom: 1px solid; border-top: 1px solid; font-size: 17px; margin-bottom: 10px; margin-top: 16px; padding: 5px 0; } .room_div { border-bottom: 1px solid #CCCCCC; padding-bottom: 5px; padding-top: 12px; } .room_name { display: inline-block; font-weight: bold; width: 165px; } .room_div a{ position: absolute; right: 40px; }
Go to /rooms
and create a few rooms, and then when you open the room's page in a new browser, you'll see something similar to this: