Chapter 4. Making It More Fun!

In the previous chapter, we created a chat room. In this chapter, we are going to improve on that chat room by giving our users a name, having multiple chat rooms, and integrating the express and socket.io sessions.

Giving names to users

Without a name for our users, chatting becomes difficult. It is impossible to identify who sent the message. So let us provide our users with a method by which they can set a nickname for themselves, so that a message from them can be identified with their name.

We have already worked with the message event in socket.io to send and receive messages. We also saw the socket.io module's predefined events. In this section, we will learn more about those events and also see how we can work with our own events. We will also see how we can save some information for the session.

Let us start by creating the user interface required for accepting a name from the user when they come to our chat room. To do this, we will modify the index.jade file by adding the following code to it:

//EXISTING LAYOUT
  section#nameform.modal
    div.backdrop
    div.popup
      div.pophead Please enter a nickname
      div.popbody
        input#nickname(type='text')
        input#setname(type='button', value='Set Name')

What we are doing here is adding a new section for the modal overlay. This section has a backdrop div tag and then a div tag for the actual form. The look and feel of this will again be defined in the style.css file, so let's update that too. Refer to the following code block while modifying the stylesheet:

//EXISTING CSS
.modal{
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  height: -moz-calc(100% - 102px);
  height: -webkit-calc(100% - 102px);
  height: calc(100% - 102px);
  left: 0;
  position: absolute;
  top: 62px;
  width: 100%;
  z-index: 1000;
}

.backdrop{
  width: 100%;
  height:100%;
  background-color: #777777;
}

.popup {
  position: absolute;
  height: 100px;
  width: 300px;
  left: -moz-calc(50% - 150px);
  left: -webkit-calc(50% - 150px);
  left: calc(50% - 150px);
  top: -moz-calc(50% - 50px);
  top: -webkit-calc(50% - 50px);
  top: calc(50% - 50px);
  background: #FFFFFF;
}

.pophead {
  background-color: #4192C1;
  color: #FFFFFF;
  font-weight: bold;
  padding: 8px 3px;
  vertical-align: middle;
}

.popbody {
  padding: 10px 5px;
}

Now when we refresh the UI, it will look like this:

Giving names to users

The username form

Next, what we will want to do is when the user enters a name and clicks on the Set Name button, send the name to the server, store it there, and prefix it to every message sent by that user. First, we will change the document ready handler to attach an event handler to the Set Name button. For this, edit public/javascripts/chat.js:

$(function(){
  $('#setname').click(function(){
    socket.emit("set_name", {name: $('#nickname').val()});
  });
});

In the previous code, we see a new socket.io API and concept, namely socket.emit. This is used to trigger custom events. The call for emit is as follows:

socket.emit(<event_name>, <event_data>);

We trigger a set_name event and pass on the value entered in the username box by the user. We also remove the send message event handler from the socket.emit declaration. We will come back to this later.

The events emitted on a socket on one side (server) will be handled on the other side of the socket (client). In our case, that is, in the previous code snippet, we trigger the set_name event on the client, so we will handle it on the server. To do this, we will edit routes/sockets.js as follows:

var io = require('socket.io'),


exports.initialize = function(server) {

  io = io.listen(server);

  io.sockets.on("connection", function(socket){

    socket.on('message', function(message){

      message= JSON.parse(message);

      if(message.type == "userMessage"){

        socket.get('nickname', function(err, nickname){

          message.username=nickname;

          socket.broadcast.send(JSON.stringify(message));

          message.type = "myMessage";

          socket.send(JSON.stringify(message));

        });        

      }

    });

    socket.on("set_name", function(data){

      socket.set('nickname', data.name, function(){

        socket.emit('name_set', data);

    socket.send(JSON.stringify({type:'serverMessage', 
    message: 'Welcome to the most interesting chat room on earth!'}));        

      });

    });

  });

}

In the practice of keeping it simple, socket.io uses the same socket.on API, which we used earlier to handle the connection or message events, to handle custom events. The data passed to the handler function will contain the data we had sent when we triggered the event.

This brings us to a new feature of socket.io, that is, attaching additional information to the socket for the session. This is achieved using the socket.set function. The call for this function is as follows:

socket.set(<name>, <value>, <optional_callback>);

In the preceding line of code, <name> is the name of the key we want to set and <value> is the value we want to set. The call to set is asynchronous; it won't be blocked till the value has been set. To perform an action where you want to ensure that the value has been set, we can pass a callback to the set method. In the previous code, we are passing the callback function that will emit another name_set custom event, and will also send the welcome message. Like the set_name event, the name_set event will be handled on the other side of the socket, which in this case is the client.

This is great. Now that the name is set, let us put it to some real use by showing it with every message so that people in our chat room know who sent the message.

To get a value set on the socket, socket.io provides a get method. We will use this get method to get the username from the socket and append it to the previous message.

Let us rework public/javscripts/chat.js to handle the name_set event and then start the actual communication:

var socket = io.connect('/'),

socket.on('name_set', function(data){
  $('#nameform').hide();
  $('#messages').append('<div class="systemMessage">' + 
                                               'Hello '+data.name+'</div>'),
  $('#send').click(function(){
    var data = {
      message: $('#message').val(),
      type:'userMessage'
    };
    socket.send(JSON.stringify(data));
    $('#message').val(''),
  });
  socket.on('message', function (data) {
    data = JSON.parse(data);
    if(data.username){
      $('#messages').append('<div class="'+data.type+
                             '"><span class="name">' + 
                             data.username + ":</span> " + 
                              data.message + '</div>'),
    }else{
      $('#messages').append('<div class="'+data.type+'">' + 
                                                     data.message + '</div>'),
    }
  });
});

$(function(){

  $('#setname').click(function(){

    socket.emit("set_name", {name: $('#nickname').val()});

  });

});

In the previous code snippet, we add two new lines of code to hide the overlay and to append the greeting to the messages area. Apart from this, we have also moved the code to handle the sending and receiving of messages to this handler, so that it is set up only after the user has set the name and avoids people from just hiding the overlay using Firebug or other similar tools. There is one last change in the message received handler; we need to check for the presence of a username in the incoming data and prefix it to the displayed message if it is.

To see the code in action, let's restart our node server and refresh the browser. Once you enter the name, it will bring up the chat room and show the greeting with the name you just entered along with the welcome message:

Giving names to users

Greeting with name

Open our chat room in another browser window and sign in as Friend this time. Enter a message in the new message box and click Send. The message appears in the message area in both the browsers. Try it from the first chat room you have opened:

Giving names to users

Chat with names

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset