0

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.

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?

index.html

<html>
<head>
    <title>Chat with socket.io and node.js</title>
    <style>
        #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;}
    </style>
</head>
<body>
    <div id="nickWrap">
        <p>Enter a username:</p>
        <p id="nickError"></p>
        <form id="setNick">
            <input size="35" id="nickname"></input>
            <input type="submit"></input>
        </form>
    </div>

    <div id="contentWrap">
        <div id="chatWrap">
            <div id="chat"></div>
            <form id="send-message">
                <input size="35" id="message"></input>
                <input type="submit"></input>
            </form>

        </div>
        <div id="users"></div>
    </div>


    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        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 < data.length; i++){
                    $users.append('<p class="sideusername">' + data[i] + "</p>");   
                }
            });

            $messageForm.submit(function(e)
            {
                e.preventDefault();
                socket.emit('send message', $messageBox.val(), function(data)
                {
                });
                $chat.append('<span class="error">' + data + "</span><br/>");
                $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 >= 0; i--){
                    displayMsg(docs[i]);
                }
            });

            socket.on('new message', function(data){
                displayMsg(data);
            });

            function displayMsg(data){
                $chat.append('<span class="msg"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
            }

            socket.on('whisper', function(data){
                $chat.append('<span class="whisper"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
            });

            $(document).on("click", ".closepopup", function() {
                $(this).parents('.chatpopup').hide();
            });

            $(document).on("click", ".sideusername", function()
            {
                var interlocutore = $(this).text();
                $chat.append('<div class="chatpopup"><table><tr><td id="interlocutore"></td><td><p class="closepopup">X</p></td></tr><tr><td colspan="2" id="msgspace"></td></tr><tr><td colspan="2"><form id="send-message-popup"> <input size="35" id="messagePopup"></input><input type="submit"></input></form></td></tr></table></div>');
                $('#interlocutore').append(interlocutore);
            });

        });
    </script>
</body>
</html>

app.js

    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();
            });
        });
    });
splunk
  • 6,435
  • 17
  • 58
  • 105

2 Answers2

7

To create a private chat using socket.IO, you need to first understand how rooms in socket.IO work. You can find loads of tutorials. You can also see this post for help.

Now you need to extend this functionality to create a private chat system. In order to do so, you need to have an unique id for each client that is either connected or is online. socket.id is an unique key that each client gets upon joining the chat.

On the client side, you can emit a name along with the message to the server. You do so like this:

socket.emit('privateMessage', 'theUserName', message);

On the server side, you could manage an array of the users who are connected and save their unique usernames or id's.

var connectedClients = {};

So each time an user connects to the chat, (for which you are probably using the new user event), save the user's id in the connectedClients.

connectedClients[username] = socket.id;

Where username is the name that is sent to the server while an user is connecting to the chat system. (I hope you know how to do this. If not, do ask me.)

Then we make a listener to listen to the privateMessage event and emit to the message to that particular user, we do:

socket.on('privateMessage', function(to, message) {
    var id = connectedClients[to];
    io.sockets.socket(id).emit('sendPrivateMessage', socket.username, message);
});

Finally, on the client side, your listener for the sendPrivateMessage receives the message and you can update your view accordingly.

Community
  • 1
  • 1
Sajib Acharya
  • 1,666
  • 5
  • 29
  • 54
1

The idea is that the server saves each socket connected to it by the username: users[socket.nickname] = socket;

so whenever a user send a message to another user - you should emit an event - send to that the username of the other user - take the socket of that user and emit him a message:

client:

socket.emit('sendPrivate','someusername','message');
socket.on('privateMsg',function(from,msg){
 //write private message from user 'from'
});

server:

socket.on('sendPrivate',function(to,msg){
   users[to].emit('privateMsg',socket.username,msg);
});
Adidi
  • 5,097
  • 4
  • 23
  • 30