title: private chat with socket.io in node.js
body: <p>I'm trying to create a chat system, where a user can send message to everybody (and this message is displayed in the div with id "chat") and I've achieved this feature. Now I'd like to implement a private chat. A user can click on another user's name on the right column (which shows all logged users), once he clicked on a username a little window will appear (div with class "chatpopup") and in this window there is a submit button and an input text to be filled with a message, once submit button has been clicked the message should be sent to the other user.</p>
  
  <p>This is what I have, if I click on a user (on the right side of the screen) the little window (chatpopup) is shown but when I try to submit the form inside this little window the app crashes.
  I'd also like to receive some hints about building a private chat, for example how can I open a new window (with the message receive) in the client side of the user that should receive the message?</p>
  
  <p>index.html</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
      &lt;title&gt;Chat with socket.io and node.js&lt;/title&gt;
      &lt;style&gt;
          #contentWrap
          {
              width:100%;
              display: none;
          }
          #chatWrap {float: left; width:80%;}
          #chat
          {
              height:500px;
              width:96%;
              border: 1px #000 solid;
              padding-left:2%;
              padding-right:2%;
          }
          #users 
          {
              margin-left:82%; width:15%;
              height:500px; 
              border: 1px #000 solid; 
              text-align:right;
          }
          #send-message {margin-top:3%; width:100%;}
          #message {width:80%;}
          .err1r{ padding-top:1%;
              color: red;
          }
          .whisper{
              color: gray;
              font-style: italic;
          }
          p.sideusername:nth-child(even) {background-color:#FAFAFA; padding-bottom:5%; padding-top:5%;}
          p.sideusername:nth-child(odd) {background-color: #f5f5f0; padding-bottom:5%; padding-top:5%;}
          .chatpopup {width:350px; height: 250px; background-color:blue;}
          #interlocutore {background-color:red; height: 30px; text-align: left;}
          #msgspace {height:150px; background-color:yellow;}
      &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
      &lt;div id="nickWrap"&gt;
          &lt;p&gt;Enter a username:&lt;/p&gt;
          &lt;p id="nickError"&gt;&lt;/p&gt;
          &lt;form id="setNick"&gt;
              &lt;input size="35" id="nickname"&gt;&lt;/input&gt;
              &lt;input type="submit"&gt;&lt;/input&gt;
          &lt;/form&gt;
      &lt;/div&gt;
  
      &lt;div id="contentWrap"&gt;
          &lt;div id="chatWrap"&gt;
              &lt;div id="chat"&gt;&lt;/div&gt;
              &lt;form id="send-message"&gt;
                  &lt;input size="35" id="message"&gt;&lt;/input&gt;
                  &lt;input type="submit"&gt;&lt;/input&gt;
              &lt;/form&gt;
  
          &lt;/div&gt;
          &lt;div id="users"&gt;&lt;/div&gt;
      &lt;/div&gt;
  
  
      &lt;script src="http://code.jquery.com/jquery-latest.min.js"&gt;&lt;/script&gt;
      &lt;script src="/socket.io/socket.io.js"&gt;&lt;/script&gt;
      &lt;script&gt;
          jQuery(function($){
              var socket = io.connect();
              var $nickForm = $('#setNick');
              var $nickError = $('#nickError');
              var $nickBox = $('#nickname');
              var $users = $('#users');
              var $messageForm = $('#send-message');
              var $messageFormPopup = $('#send-message-popup');
              var $messageBox = $('#message');
              var $messageBoxPopup = $('#messagePopup');
              var $chat = $('#chat');
  
              $nickForm.submit(function(e){
                  e.preventDefault();
                  socket.emit('new user', $nickBox.val(), function(data){
                      if(data){
                          $('#nickWrap').hide();
                          $('#contentWrap').show();
                      } else{
                          $nickError.html('That username is already taken!  Try again.');
                      }
                  });
                  $nickBox.val('');
              });
  
              socket.on('usernames', function(data){
                  $users.empty();
                  for(var i=0; i &lt; data.length; i++){
                      $users.append('&lt;p class="sideusername"&gt;' + data[i] + "&lt;/p&gt;");   
                  }
              });
  
              $messageForm.submit(function(e)
              {
                  e.preventDefault();
                  socket.emit('send message', $messageBox.val(), function(data)
                  {
                  });
                  $chat.append('&lt;span class="error"&gt;' + data + "&lt;/span&gt;&lt;br/&gt;");
                  $messageBox.val('');
              });
  
              $messageFormPopup.submit(function(e)
              {
                  e.preventDefault();
                  socket.emit('send popup message', $messageBoxPopup.val(), function(dataPopup)
                  {
  
                  });
                  $messageBoxPopup.val('');
              });
  
              socket.on('load old msgs', function(docs){
                  for(var i=docs.length-1; i &gt;= 0; i--){
                      displayMsg(docs[i]);
                  }
              });
  
              socket.on('new message', function(data){
                  displayMsg(data);
              });
  
              function displayMsg(data){
                  $chat.append('&lt;span class="msg"&gt;&lt;b&gt;' + data.nick + ': &lt;/b&gt;' + data.msg + "&lt;/span&gt;&lt;br/&gt;");
              }
  
              socket.on('whisper', function(data){
                  $chat.append('&lt;span class="whisper"&gt;&lt;b&gt;' + data.nick + ': &lt;/b&gt;' + data.msg + "&lt;/span&gt;&lt;br/&gt;");
              });
  
              $(document).on("click", ".closepopup", function() {
                  $(this).parents('.chatpopup').hide();
              });
  
              $(document).on("click", ".sideusername", function()
              {
                  var interlocutore = $(this).text();
                  $chat.append('&lt;div class="chatpopup"&gt;&lt;table&gt;&lt;tr&gt;&lt;td id="interlocutore"&gt;&lt;/td&gt;&lt;td&gt;&lt;p class="closepopup"&gt;X&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" id="msgspace"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;&lt;form id="send-message-popup"&gt; &lt;input size="35" id="messagePopup"&gt;&lt;/input&gt;&lt;input type="submit"&gt;&lt;/input&gt;&lt;/form&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;');
                  $('#interlocutore').append(interlocutore);
              });
  
          });
      &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>app.js</p>
  
  <pre><code>    var express = require('express'),
      app = express(),
  
  server = require('http').createServer(app),
  io = require('socket.io').listen(server),
  mongoose = require('mongoose'),
  users = {};
  server.listen(3000);
  
      mongoose.connect('mongodb://localhost/chat', function(err)
      {
          if(err)
             console.log(err);
          else console.log('Connected to mongodb!');
      });
  
      var chatSchema = mongoose.Schema(
      {
          nick: String,
          msg: String,
          created: {type: Date, default: Date.now}
      });
  
      var Chat = mongoose.model('Message', chatSchema);
      app.get('/', function(req, res)
      {
          res.sendfile(__dirname + '/index.html');
      });
  
      io.sockets.on('connection', function(socket)
      {
          var query = Chat.find({});
          query.sort('-created').limit(8).exec(function(err, docs)
          {  // carico gli ultimi 8 messaggi in ordine di data
              if(err) throw err;
              socket.emit('load old msgs', docs);
          });
  
          socket.on('new user', function(data, callback)
          {
              if (data in users)
                  callback(false);
              else
              {
                  callback(true);
                  socket.nickname = data;
                  users[socket.nickname] = socket;
                  updateNicknames();
              }
          });
  
  
          function updateNicknames()
          {
              io.sockets.emit('usernames', Object.keys(users));
          }
  
          socket.on('send message', function(data, callback)
          {
                  var msg = data.trim();
                  var newMsg = new Chat({msg: msg, nick: socket.nickname});
                  newMsg.save(function(err)
                  {
                      if(err) throw err;
                      io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
                  });
  
                  socket.on('disconnect', function(data)
                  {
                      if(!socket.nickname) return;
                      delete users[socket.nickname];
                      updateNicknames();
                  });
          });
  
  
          socket.on('send popup message', function(data, callback)
          {
              /*var msgPopup = dataPopup.trim();
              if (msgPopup !== "")
                  users[interlocutore].emit('whisper', {msg: msgPopup, nick: socket.nickname});
              */
                  var msg = data.trim()+" hello";
                  var newMsg = new Chat({msg: msg, nick: socket.nickname});
                  newMsg.save(function(err)
                  {
                      if(err) throw err;
                      io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
                  });
              socket.on('disconnect', function(data)
              {
                  if(!socket.nickname) return;
                  delete users[socket.nickname];
                  updateNicknames();
              });
          });
      });
  </code></pre>