Using Socket.IO with angularjs

As we did with D3.js, we want to integrate Socket.IO properly into the client application. In other words, encapsulate it as a service and make it injectable. Therefore, we create a new factory for Socket.IO in the app.js file:

/* src/app.js */
app.factory('socket', function () {
  var socketio = io.connect();
  return socketio;
});

In our example, we will use the .on() method to listen for events propagated from the server and the .emit() method to propagate events to the server. To inform angularjs about changes on the scope (outside of the angularjs application), we need to call $scope.$apply() to trigger a digest circle that updates all scope variables. Let’s write a wrapper for the .on() and .emit() functions that automatically update $rootScope. and thereby all scope variables of the application:

/* src/app.js */
angular.module('myApp', ['myChart'])
// Socket.IO Wrapper
.factory('socket', ["$rootScope",
  function($rootScope) {
    var socketio = io.connect();
    return {
      on: function (e, callback) {
        socketio.on(e, function() {
          var args = arguments;
          $rootScope.$apply(function() {
            callback.apply(socketio, args);
          });
        });
      },
      emit: function (e, data, callback) {
        socketio.emit(e, data, function() {
          var args = arguments;
          $rootScope.$apply(function() {
            if (callback) {
              callback.apply(socketio, args);
            }
          });
        });
      }
    };
  }
])

The preceding implementation checks and updates the state of $rootScope on every callback of the .on() and .emit() function automatically.

Now, we can inject Socket.IO into the controller and send and receive data; let’s try it:

/* src/app.js */
...
.controller('MainCtrl', ["$scope", "socket",
  function ($scope, socket) {
    $scope.logs = [{
      name: 'apache.access',
      path: 'var/log/apache/access.log'
    }];

    angular.forEach($scope.logs, function(log){

      socket.emit('watch', {
        name: log.name,
        path: log.path
      });

      socket.on(log.name, function(data){
        console.log("Received: " + data);

        // Now we can process the data
      });
    });
  }
]);

Although my browser has to struggle a little to display all the content from the Apache access log, we see that it works. This means that we receive the string of the correct data log from the server if Apache is running and the access log is updated; also, the file is reloaded. Perfect. Now, we can already think of processing the log file. Keep in mind that in a more advanced scenario, we will just transfer the small changes of the log files instead of 5 MB, of logs. It’s worth mentioning that you should implement security mechanism for the HTTP connection and for the WebSockets connection as well.