Socket.IO and Angular.JS

Ryan Tucker

What is socket.io?

Socket.IO is a NodeJS package.

Socket.IO aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms. It's care-free realtime 100% in JavaScript.

Socket.io in practice

  • Use Websockets everywhere
  • Don't worry about the details
  • It just works
  • Useful advanced features like multiplexing

how do I use it?

var io = require('socket.io').listen(80);io.sockets.on('connection', function(socket) {  socket.emit('news', {hello: 'world' });  socket.on('my other event', function(data) {    console.log(data);  });});
<script src="/socket.io/socket.io.js"></script><script>  var socket = io.connect('http://localhost');  socket.on('news', function(data) {    console.log(data);    socket.emit('my other event', {my: 'data'});});</script>

Server

Client

That's great, what can I really do with it?


192.168.1.200:9000

Why Angular and socket.io?

  • Model, View, Whatever separation of concerns
  • Easily wrap Socket.IO in an Angular service for reusability and to keep third party libraries isolated from the rest of the application

Let's Build a socket.io service

  • Connection
  • Disconnection
  • Listen for events
  • Send messages

Connection/Disconnection

Socket.IO exposes two aptly names methods:
  • connect
  • disconnect

var mySocket = io.connect('http://localhost/');
mySocket.disconnect();

Listening for event

To listen for an event we use the familiar .on('eventName', cb) convention.

mySocket.on('userJoined', function(data) {  console.log('A user joined!', data);});

Sending an event

So you want to send something back to the server?

In Socket.IO vernacular we emit an event and can pass some data along with it.

 mySocket.emit('updateUserName', {name: 'My New Name' });

wrapping it up in angular land

We'll design an event driven service . Let's start from the top.

 angular.module('wsDemo').service('SocketService', function($rootScope) {   var socket; // Our future socket   var self = this;
this.connect = function connect() { socket = io.connect('http://localhost/'); listenForEvents(socket); // Coming in a bit };
this.disconnect = function disconnect() { if(socket) { socket.disconnect(); } };

Let's listen for some events


function listenForEvents(ws) {  ws.on('userJoined', function(data) {    $rootScope.$apply(function() {      // Let's broadcast an Angular event      $rootScope.$broadcast('userJoined', data);    });  });
ws.on('userLeft', function(data) { $rootScope.$apply(function() { $rootScope.$broadcast('userLeft', data); }); });}

Watch out!

We must wrap external calls in $apply since we are out of the Angular digest cycle.

 ws.on('userLeft', function(data) {   $rootScope.$apply(function() {     $rootScope.$broadcast('userLeft', data);   }); );

let the world hear you

Sending events

 // Send the given message this.sendMessage = function(message) {   if (socket) {     socket.emit('message', message);   } }

Building the chat demo

What's left to do?

  • Build a users controller
  • Build a chat controller
  • Build a users service
  • Build a chat service
  • Some HTML to glue it all together

chat controller

function ($scope, ChatService, SocketService) {
        $scope.messages = ChatService.messages;

        function sendMessage(message) {
            ChatService.sendMessage(message);
            // Clear the message
            $scope.msgToSend = '';
        };

        $scope.sendMessage = sendMessage;
        $scope.messageKeyUp = function messageKeyUp($event, message) {
            if ($event.keyCode === 13 && $scope.userForm.$valid) {
                sendMessage(message);
            }
        };
    });

chat Service

 .service('ChatService', function chatService($rootScope, SocketService, UsersService) {  this.messages = [];  var self = this;
function messageReceived(event, data) { // Filter out our own messages if(UsersService.myUser.id !== data.id) { self.messages.push(data); } }
function sendMessage(message) { self.messages.push(message); SocketService.sendMessage(message); } $rootScope.$on('message', messageReceived); return this;}

users controller

 .controller('UsersCtrl', function ($scope, UsersService) {
        $scope.users = [];

// Watch for a change in the users $scope.$watch(function() { return UsersService.users; }, function(val) { $scope.users = val; }, true); });

users service

 .service('UsersService', function chatService($rootScope) {
        // Array to hold our users
        this.users = [];
        this.myUser = {};
function userJoined(event, data) { ... } function userLeft(event, data) { ... } function userEdited(event, data) { ... } function userList(event, data) { ... } function setUserId(event, data) { ... } function disconnected(event, data) { ... }
$rootScope.$on('userJoined', userJoined); ... $rootScope.$on('disconnected', disconnected); return this;

A bit of HTML

http://192.168.1.200:9000/

how would I improve this?

  • Make the service more generic
  • Don't hardcode events in the main socket service
  • Consider a pub-sub model to notify interested parties

Check out Brian Ford's Angular-Socket.IO Library for a more comprehensive library at https://github.com/btford/angular-socket-io

Questions?

All slides are publicly available at http://slid.es/ryantucker/socket-io-and-angular-js.

The code is available at https://github.com/rtucker88/ws-angular.

I'll put links to this on Meetup.com after the talk!
Made with Slides.com