March 8, 2015

A sample chat app using node.js and socket.io

Chat app using node.js and socket.io

NodeJS is an extremely useful technology, and provides us with a great deal of power and joy, especially when considering the fact that we can write pure JavaScript. As you are going to see, with only a few lines of code, we will manage to write a fully functional real time chat application. Pretty neat!

In this we are going to write a real-time chat application using Node.js and Socket.IO. MongoDB is our database solution. We will be doing the front end and just using Node.js to handle the actual request to the server to store the data. You can run the chat locally with node, or push it to heroku or a different cloud service provider.

Before beginning, all dependencies are declared in the package.json file. They are not included in the repo and you will have to run npm install to get them.

Running the app:

Before beginning the design and implementation part, let's look out how to run this app. To run the chat app, you need to have Node.js installed, so that the node and npm commands can be called from your terminal.

Download the code from my repo and unzip the archive to a folder called chat. After this, navigate to the folder you’ve created from your terminal: cd chat/

Then, run this command to download all the libraries that the chat system uses: npm install

This will install all the dependencies that are described in package.json.

When it’s done, run the following command to start your very own local chat: node server.js

Hit ctrl+c to stop it. The bad news is that you can’t invite your friends to your chat, since it is running on your own computer. To fix this, you need to run it on a web server. Setting up a web server by yourself to run node is not a very straightforward process and involves a good deal of server administration skills. Luckily, it is very easy to get started with cloud platforms like Heroku.

Design:

First thing we are going to do is design the chat app. If you already have a design in mind you can go ahead. The important thing to remember is that when it comes to implement in the JavaScript you need to choose your selectors based on your class name or id or whatever it maybe.

HTML

<div class="chat">
   <input type="text" class="chat-name" placeholder="Enter your name" />
   <div class="chat-messages"></div>
   <textarea placeholder="Type your message"></textarea>
   <div class="chat-status">Status: <span>Idle</span></div>
</div>

A simple elegant chat theme.

CSS

body,
input,
textarea {
    font: 13px "Trebuchet MS", sans-serif;
}

.chat {
    max-width: 300px;
    margin: 0 auto
}

.chat-name,
.chat textarea,
.chat-messages {
    border: 1px solid #bbb;
    width: 100%;
    padding: 10px;
}

.chat-messages {
    height: 300px;
    overflow-y: scroll;
}

.chat-message {
    margin-bottom: 10px;
}

.chat-name,
.chat textarea {
    outline: none;
}

.chat-name {
    border-bottom: 0;
}

.chat textarea {
    border-top: 0;
    max-width: 100%;
}

.chat-status {
    color: #bbb
}

Now the HTML and CSS is over. Now what we are going to do is the implementation of the app. Having Node.js installed, install MongoDB on your system for your database. The instructions on the website are very straight forward. Go ahead and install them, following the instructions given there.

Inserting data:

Create two variables mongo and client

var mongo = require('mongodb').MongoClient,
    client = require('socket.io').listen(3000).sockets;

The MongoClient is going to make us connect to the database and do various sort of things. Then we will use listen(port_number) method and listen on specific port. This can be absolutely any port.

Every time a client is connected and we listen for connections here.

client.on('connection', function(socket) {
    console.log('Someone has connected');
});

What we also want to do is wrap this in a connection to a MongoDB database.

mongo.connect('mongo://127.0.0.1/Name_of_the_database', function(err, db) {
    if(err) throw err;
    client.on('connection', function(socket) {
    
    });
});

This will handle any errors. Once we have connected to our database then we want to start looking for connections.

Now we are going to do is listen for the input.

var col = db.collection('messages');

socket.on('input', function(data) {
    var name = data.name,
        message = data.message;
});

Once we have connected to our database, we want to go ahead and obtain the collection we already have using db.collection.

Now we have to define what we want to insert.

col.insert({name: name, message: message}, function() {
    console.log('Data Inserted');
});

Let's introduce a little bit of validation if the name or the message field is empty or not. This basically checks there is no white space.

var whitespacePattern = /^\s*$/;

if(whitespacePattern.test(name) || whitespacePattern.test(message)) {
    console.log('Invalid');
} else {
    //Insert the data
}

Sending messages:

Next step we are going to allow user to enter messages alone with their name and have that sent to Node.js server and inserted subsequently into MongoDB database.

I am going to use an useful function called getnode. This is going to return a query selector based on what we parse through it with. This is not going to work on old browsers and older versions of IE.

(function() {
    var getNode = function(s) {
        return document.querySelector(s);
    },

    textarea = getNode('.chat textarea'),
    chatName = getNode('.chat-name '),
})();

More importantly we want to go ahead and try connection to our server. If this fails we can't do anything. So this is very important.

try {
    var socket = io.connect('http://127.0.0.1:3000');
} catch(e) {
    //Set status to warn user
}

What we are going to do here is check if socket is undefined

if(socket !== undefined) {
    console.log('Ok');
}

Now what we are going to do is, if enter key is pressed message is to be sent to the server along with the name appears as well. If shift + enter key is pressed it should go to next line.

textarea.addEventListener('keydown', function(event) {
    var self = this,
        name = chatName.value;

    if(event.which === 13 && event.shiftKey === false) {
        console.log('Sent')
    }
});

Outputting Statuses:

Let's define a method which is going to send status.

sendStatus = function(s) {
    socket.emit('status', s);
};

In our case we send a status if either your name or message field is empty.

sendStatus('Name and message is required.');

Now we have to listen for status. We have to check if it's an object. If it's an object we have to construct the message. And after some seconds of displaying the status the default status will be displayed i.e Idle

var status = getNode('.chat-status span'),
    statusDefault = status.textContent,
    setStatus = function(s) {
        status.textContent = s;

        if(s !== statusDefault) {
            var delay = setTimeout(function() {
                setStatus(statusDefault);
                clearInterval(delay);
            }, 3000);
         }
    };

socket.on('status', function(data) {
    setStatus((typeof data === 'object') ? data.message : data);

    if(data.clear === true) {
        textarea.value = '';
    }
});

Output chat messages:

Here we will retrieve the saved data from the database and display it in chat box.

col.find().limit(100).sort({_id: 1}).toArray(function(err, res) {
    if(err) throw err;
    socket.emit('output', res);
});

Here i have limited the number of messages to display. You can give any number here limit(100). And we sort it by id and show is opposite order in the sort of last first.

Now we have to listen for output and loop through the data.

socket.on('output', function(data) {
    if(data.length) {

        for(var x = 0; x < data.length; x = x + 1) {
            var message = document.createElement('div');

            message.setAttribute('class', 'chat-message');
            message.textContent = data[x].name + ': ' + data[x].message;

            messages.appendChild(message);
            messages.insertBefore(message, messages.firstChild);
        }
    }
});

Conclusion:

We've got a styled element message and name that is sent through Node.js. We've got server setup. It validates and sends messages back to the client success or not. Basically all of this put together creates a working chat. But there is much more that can be improved on it. You can change the theme of it. You can create a private chat room. You can create a secure chat room by creating passwords.

Clone my Repo

git clone https://github.com/vivinantony/chat.git

View Code

No comments:

Post a Comment

Popular Posts

Views