Angular, Express, Node and Sock.js Chat application

P.Madhanasekaran

Earlier we saw a “JQuery, Express, Node and Socket.io chat application”. For a chat application, now we will replace JQuery and Socket.io with Angular and Sock.js in the above stack.

The difference between jQuery and Angular can be summarized as under:  jQuery is a library. It is one of the best tools to manipulate  elements on a web page .You know when a Browser loads a web page,  it parses that into a tree of DOM objects. JQuery is an excellent tool to read and manipulate DOM objects in a web page. Angular.js is a framework, which provides a lot of features that we don't get when using a library like JQuery.

  1. MVW pattern (similar to MVC)
  2. Two way data binding
  3. Templates
  4. Form Validations
  5. Deep Linking for dynamic pages
  6. Communication with server
  7. Reusable components and localization.

But it is easier to use JQuery as the code to directly manipulate the DOM elements is more straight-forward. When you use Angular, you should not directly manipulate DOM in a web page. It is the job of directives. You can code a “custom” directive or use the built-in ones. You should bind the DOMs in view to models in a controller through these directives and the two-way data binding in Angular will take care of the rest. They say that you can use jQuery with AngularJS to build some very complex and good web apps. But for a small chat application, use of both may be an over-kill.

Sock.js :

We already had an article on it. It is a WebSocket emulation library like socket.io; but it is simpler with lesser features when compared to socket.io- but a closer implementation of WebSocket protocol. Soft real time applications like Gaming, Collaboration (live wikis), Dashboards (financial apps), Tracking (watch user actions), Presence(chat), etc  that require “low latency two way communication” are good fits for Web socket. The aim of WebSocket is “to provide a two way bi-directional fully duplex” communication channel. Web-socket uses “HTTP” only for initial handshake and thereafter “TCP” connection is used. So, with it, one can provide low latency high speed connections. But older browsers without support for Web Socket are still in wide use. The emulation libraries like sock.js are meant to handle the situation. In newer browsers they use WebSocket; in older browsers that don’t support WebSocket, these emulation libraries use “older HTTP hacks” like Comet to provide real-time communication.

 

Install express-generator:

As mentioned in the earlier article we can convert the earlier sample into a basic “Chat” app, with a few modifications. As we did earlier, we will use express-generator to generate a skeleton project.

You can change to the folder meant for your express projects- in my case E:\ExpPro-II - and execute
express --ejs ChatApp

The generator will generate skeleton project “ChatApp” with “ejs” view engine. The reason for using
“ejs-embedded JavaScript template ” instead of “jade” was  explained in the earlier sock.js article. “Ejs” is nothing but html with “ejs-tags”. For using Angular we can easily replace ejs-tags with Angular directives.

Change to ChatApp in Command Prompt and execute
npm install

and install the dependencies. To add sock.js execute
   npm install sockjs –save

To see whether our project is working you can execute
node app

and navigate in the browser to
localhost:3000

you will see a “Welcome” message. You can stop the express server and carry out the following changes to the skeleton project.

Changes in app.js:

As mentioned in the earlier article, the generated code for “app.js” contains code for adding and using various middlewares like “body-parser” etc and error handling. The file is exported to another module “bin/www” which actually contains the code for creating the HTTP/express server. We will delete that file and modify app.js to create the server in “app.js” itself, as we did in the earlier sock.js sample.

 

app.js

var app = express();    // part of generated code
…………
…………
 //after this included portion
var sockjs = require('sockjs');    //------2)

var connections = [];

var chat = sockjs.createServer();  //--------2)
chat.on('connection', function(conn) {  //--------3)
connections.push(conn);
var number = connections.length;
conn.write("Welcome, User " + number);
conn.on('data', function(message) {
for (var i=0; i < connections.length; i++) {
connections[i].write("User " + number + " says: " + message);
}
});
conn.on('close', function() {
for (var i=0; i < connections.length; i++) {
connections[i].write("User " + number + " has disconnected");
}
});
});

var server = http.createServer(app);  //--------1)


server.listen(3000, '0.0.0.0');  

console.log(' [*] Listening on 0.0.0.0:3000' );


chat.installHandlers(server, {prefix:'/chat'});    //------2)

 

The code is similar to the one used in the earlier sample except the name given to the server instance and the use of an array to push all the client connections.

  1. As in the earlier sample, while creating a http server we have passed the express as an argument and to the listen() method in express, the port number is passed. The returned “express server/HTTP server” is stored in the variable “server”.
  2. Sock.js server side library is required and used. To the installHandlers() method in sockjs server, we are passing the express server as a parameter.
  3. This part is different from the earlier code. The server pushes the connections from clients into an array, as a separate connection is made for every client. A client is recognized through their numbers and a customized welcome is sent. We will discuss more about it in the later portion of this article.

Changes in index.ejs   As mentioned in the earlier article, though “index.ejs” was generated by Express we are modifying it to use “Angular” and the client-side “sock.js”.

index.ejs

<!DOCTYPE html>
<html ng-app>
<head>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>  //----1)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.11/angular.min.js"></script>

  <script src="javascripts/chat.js"></script>  //------2)

  </head>

  <body>

  <div ng-controller="ChatCtrl">
<h1>ChatApp</h1>
<ul>
<li ng-repeat="message in messages track by $index">{{message}}</li>
</ul>

    <form ng-submit="sendMessage()">
<input type="text" ng-model="messageText" placeholder="Type your message here" />
<input type="submit" value="Send" />
</form>
</div>

  </body>
</html> 


You can see that this is nothing but the earlier “index.ejs” . The controller code we saw in the earlier sock.js/ angular applications is put in the file “chat.js”, the code for which is given below:

/public/javascripts/chat.js

var sock = new SockJS('http://localhost:3000/chat');
function ChatCtrl($scope) {
$scope.messages = [];
$scope.sendMessage = function() {
sock.send($scope.messageText); //------1)
$scope.messageText = "";
};

  sock.onmessage = function(e) { 
$scope.messages.push(e.data);
$scope.$apply();  //-------2)
};
}


This is also not different from the earlier controller code.

  1. The data received from the sock server is pushed into the $scope.messages array[] by the onmessage() event of sock client.

2)  As mentioned earlier, $scope.apply() is responsible for making sure that the bindings are updated and the view reflects all those changes AngularJS does this internally at regular intervals within its lifecycle, but if the call comes from outside (a sock event), scope.$apply just takes note, but does nothing. That is why we have to explicitly call scope.$apply to tell it, to do this right now.

Run the application

You can run the application by executing
node app

You will see the message “express server is listening on port 3000”.Now you open two browser windows 1) Chrome 2)Firefox and can navigate to

localhost:3000

You will see Figure 1 and Figure-2.You can send message from Chrome to Firefox and vice-versa. After that your browser windows may look as in Figure-3 and Figure-4.

Data-Flow:

The data flow happens as shown below:

In general remember one thing. When the server waits for connections from many clients or writes messages meant for many clients, event-handlers and methods from the server library are used. To receive or send data from a particular client, the server uses the event-handler or method from the client library as both the server and the client has to use the same bi-directional connection.

The control flow of the program is as under:

  1. Clients 1 to n connect to server.
  2.  The server is triggered by the server side event -on(connection).
  3.  The server not only pushes the “conn” object received from a client into the server’s connection[] array but also  uses write() in  the conn object received from a client to write welcome message to that client..
  4. Then the client invokes send() in the sock client library to send the message written by a user.
  5. Now the server sees the on(data) event in the conn object received from a client.
  6. This triggers the server to invoke a write()  in the server library (in server’s connection[] array ).
  7. As an effect of this write, is “onMessage” event is triggered in all connected clients.
  8. Then the clients push into their message [] arrays, the message written by the server in the connections [] array. The clients also put the message [] arrays in $scope provided by Angular to the controller, so that the view can access it.

Conclusion:

For soft real time applications that require two way communication and quicker updates, Web-socket is the “ideal” solution. But the problem is the wider use of older browsers that don’t support it. Sock.js used to handle the situation. The ease with which the earlier sample was converted into a rudimentary chat app shows that web socket and the emulation libraries are meant for such applications that require fully duplex two way communication channels- like chats, interactive games, online trading etc.



 

This article is written by P. Madanasekaran. For more information you can send an email to sekaran.madhan@gmail.com








}