We've talked about how Node is well-suited for real-time applications, but so far our CRUD apps haven't really required a real-time component. Today, all that changes. Let's explore socket.io, a realtime application framework for Node.
Let's use socket.io
to build a simple chat room. We'll roughly follow the outline for the tutorial in the socket.io docs, but we'll do things a bit differently since y'all are so awesome at Node. To get started, create a directory for your project (maybe chat-example
), cd into it, and start a new node project. For now, you'll only need to install three node modules: express
, ejs
, and socket.io
.
Once you're set up, require express
in your app.js
in the usual way. In order to set up socket.io
, you'll need a couple of new lines in your code:
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
res.render('index');
});
server.listen(3000, function(){
console.log('listening on localhost:3000');
});
To start building our chat room, let's create an input field for our users to type into, as well as a submit button:
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO chat</title>
<link rel="stylesheet" href="/stylesheets/app.css">
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
Notice that we've linked to a stylesheet, so that we can make our app not look terrible. Here's some simple styling to get you started:
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
To make use of io
in our app.js
, we'll use the on
method to listen for connections to our server:
io.on('connection', function(socket){
console.log("someone entered the chat room!");
});
This should work the first time you go to localhost:3000, but not on subsequent attempts. To log to the console whenever you visit the chat room, you need to add some client-side javascript as well. Let's append a few script tags to our body
:
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="/javascripts/chat.js"></script>
Inside of our chat.js
file, let's initialize socket.io on the client side:
chat.js
$(function() {
var socket = io();
});
(We'll need jQuery in the next step.)
With this client-side javascript in place, you should see your message getting logged to the console every time you visit localhost:3000
!
Right now our chat app is pretty lame. Let's use jQuery and socket.io to spice things up. Try to do the following without looking at the socket.io tutorial:
In your chat.js
:
- Use jQuery to add a listener for form submissions.
- In the callback to your listener, prevent the default submit action; then,
- Use the
socket.emit
method to send the message the user typed to the server.socket.emit
takes two arguments: the first is just the name you want to give to the event you're passing (let's call it'chat message'
), while the second is the actual data you want to pass (how can you get the user's message using jQuery?). - After
emitting
, clear the input field. Our chat app would be pretty clunky if users had to delete their old messages before they could type in new ones.
To be sure that your messages are being sent correctly, in your app.js
:
- replace your
console.log
inside of yourio.on
callback with a listener for messages from the client. In this case, you should usesocket.on
, which takes two arguments: the first is the name of the event it should listen for (i.e.'chat message'
), while the second is a callback. Have your callback log the received message to the console.
Here's where the real-time magic kicks in. Let's make it so that when our server receives a message, it turns around and shows that message to everyone who's in the chat room. To do this...
In your app.js
:
- Instead of using a
console.log
in yoursocket.on
callback, useio.emit
to emit the message. Once again, this method takes two arguments: the first is the name of the event, the second is the data you want to emit.
In our chat.js
- Just like in your server-side code, you have access to a
socket.on
method on the client side. In this case, when the socket sees a'chat message'
event, it should append anli
to the page'sul
with the message contents.