Build Chat Application On MEA2N Stack - Part One

In this article we are going to build a basic chat application on NodeJs platform using Express and Angular 2. For saving chat history we will use MongoDB. We will be using socket.io for communication between server and client.

In this article, we are going to build a basic chat application on Node.js platform using Express and Angular 2. For saving chat history, we will use MongoDB Atlas. We will be using socket.io for communication between Server and Client.

Prerequisites

Initial Setup

Create a new folder for the application. Name it ‘chat-app’. Open ‘chat-app’ folder in Visual studio code. Open terminal and run ‘npm init’ command. Fill details as mentioned in screen shot provided. It will create ‘package.json’ under ‘chat-app’ folder.

 

We have initialized the node application. Now we will install express, ejs and socket.io by running ‘npm install express ejs socket.io --save’ command. The --save option instructs NPM to include package under dependencies section of package.json.

To create an Angular application, we need to install angular cli. We will run ‘npm install --save-dev @angular/cli@latest’ command to install angular cli. After installing all required packages, our package.json will look like

  1. {  
  2.     "name""mean_chat_app",  
  3.     "version""1.0.0",  
  4.     "description""chat application using MEA2N stack.",  
  5.     "main""starter.js",  
  6.     "scripts": {  
  7.     "test""echo \"Error: no test specified\" && exit 1"  
  8.     },  
  9.     "author""Akshay Deshmukh",  
  10.     "license""ISC",  
  11.     "dependencies": {  
  12.     "ejs""^2.5.7",  
  13.     "express""^4.15.4",  
  14.     "socket.io""^2.0.3"  
  15.     },  
  16.     "devDependencies": {  
  17.     "@angular/cli""^1.3.2"  
  18.     }  
  19. }  
Now create js file under ‘chat-app’ folder and name it as ‘starter.js’. This will be the entry point of our application (mentioned while nmp init).

We will create our Angular application by executing ‘ng new ng-app’ command. It will create ‘ng-app’ folder under ‘chat-app’ folder and populate all supporting files for the Angular application. Run ‘ng build’ command to build the Angular application. It will create ‘dist’ folder with build output files.

Now we are ready with initial setup. We will start with coding…

Implementation – Server side

Open ‘starter.js’ and start writing your code

  1. const path = require("path");    
  2. const express = require("express");    
  3. const ejs = require("ejs");    
  4. const appServer = express();  
  5. appServer.engine("html", ejs.renderFile );  

Here we are loading path, express and ejs modules using require function.We have created object of express as ‘appServer’ by calling ‘express()’ method. Then we set ejs as template engine for express. Default engine of express is Jade.

  1. appServer.set("views", path.join(__dirname, "ng-app/dist"));  
  2. appServer.use(express.static(path.join(__dirname, 'assets')));  
  3. appServer.use(express.static(path.join(__dirname, 'ng-app/dist')));  

We will set views path for express server as ‘ng-app/dist’, which is our output directory of the Angular app. Then we will set path for static files. This means if there is any static content mentioned on page; express server will try to fetch it from these folders.

  1. appServer.get("*", (request, response) => {  
  2.    response.render("index.html");  
  3. });  
  4.   
  5. const serverPort = 9696;  
  6. appServer.listen(serverPort, ()=>{  
  7.    console.log("Server is started and listening on port "+ serverPort);  
  8. });  

We will add route to express server as ‘*’. It means for any request it will render ‘index.html’ from views folder of express server; which is ‘ng-app/dist’. Then server will start listening on port 9696 for requests.

  1. const socketsPort = 9697;  
  2. const sockets = require("socket.io").listen(socketsPort).sockets;  
  3.   
  4. sockets.on("connection", (client) => {  
  5. console.log(socket.client.id + " is connected.");  
  6. client.emit("connected", { clientId: socket.client.id });  
  7. client.on("send_message", (message) => {  
  8.     console.log(socket.client.id + ":)" + message);  
  9.     sockets.emit("new_message", { from: socket.client.id, text: message });  
  10.     });  
  11. });  

After web application server, we will start listening on port 9697 for socket connection. If any client is connected, ‘connection’ event is triggered and on this event we will log ‘client id’. Then emit event ‘connected’ for that client with its client id as data. Then add listener for ‘send_message’; which will log message with client id and emit that message along with sender id to other clients.

Implementation – Client side

Now open index.html under path ‘chat-app/ng-app/src’. Add references for bootstrap, font-awesome css and socket.io js file. I have also added chat.ico icon file in assets folder under ‘chat-app’. Index.html file will look like

  1. <!doctype html>  
  2. <html lang="en">  
  3.   
  4. <head>  
  5.     <meta charset="utf-8">  
  6.     <title>Chat!</title>  
  7.     <base href="/">  
  8.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  9.     <link rel="icon" type="image/x-icon" href="chat.ico">  
  10.     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">  
  11.     <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous"> </head>  
  12.   
  13. <body>  
  14.     <app-root></app-root>  
  15. </body>  
  16. <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>  
  17.   
  18. </html>  

Open app.component.ts from path ‘ng-app/src/app’. Add OnInit, ElementRef, ViewChild, AfterViewChecked to import from angular core. Then import all from socket.io-client.

  1. import {  
  2.     Component,  
  3.     OnInit,  
  4.     ElementRef,  
  5.     ViewChild,  
  6.     AfterViewChecked  
  7. } from '@angular/core';  
  8. import * as socket_io from 'socket.io-client';  
  9. @Component({  
  10.     selector: 'app-root',  
  11.     templateUrl: './app.component.html',  
  12.     styleUrls: ['./app.component.css']  
  13. })  
Add properties to AppComponent class. Update AppComponent class to implement OnInit and AfterViewChecked.
  1. export class AppComponent implements OnInit, AfterViewChecked {    
  2.     title = 'Chat Application';    
  3.     message = "";    
  4.     messages = [];    
  5.     socket;    
  6.     socketId;    
  7.     @ViewChild("chatwindow"private chat_window: ElementRef;    
On initialization of component, we are creating socket client and connecting with socket server which we have created in starter.js. Here I have mentioned localhost but to access it from other machines we will give ip of hosted machine. Here client is listening for events ‘new_message’ and ‘connected’.

  1. ngOnInit() {  
  2.     this.socket = socket_io("http://localhost:9697");  
  3.     // this.socket = socket_io("http://10.21.15.68:9697");    
  4.     this.socketId = this.socket.socketId;  
  5.     this.socket.on("new_message", (message) => {  
  6.         this.messages.push(message);  
  7.     });  
  8.     this.socket.on("connected", (data) => {  
  9.         this.socketId = data.clientId;  
  10.     });  
  11. }  
On view check chat window will be scrolled down to show the latest messages.
  1. ngAfterViewChecked() {  
  2.     this.chat_window.nativeElement.scrollTop = this.chat_window.nativeElement.scrollHeight;  
  3. }  
SendMessage() function will emit ‘send_message’ event to server with message contents.

sendSmily() function will also emit ‘send_message’ event but with specific smiley message content.

  1. sendMessage = () => {  
  2.     this.socket.emit("send_message"this.message);  
  3.     this.message = "";  
  4. };  
  5. sendSmily = () => {  
  6.     this.socket.emit("send_message"":)");  
  7. };  
  8. }  
Open app.module.ts file from path ‘ng-app/src/app’ and import FormsModule from angular core. Add it to imports array.
  1. import {  
  2.     BrowserModule  
  3. } from '@angular/platform-browser';  
  4. import {  
  5.     NgModule  
  6. } from '@angular/core';  
  7. import {  
  8.     FormsModule  
  9. } from '@angular/forms';  
  10. import {  
  11.     AppComponent  
  12. } from './app.component';  
  13. @NgModule({  
  14.     declarations: [  
  15.         AppComponent  
  16.     ],  
  17.     imports: [  
  18.         BrowserModule, FormsModule  
  19.     ],  
  20.     providers: [],  
  21.     bootstrap: [AppComponent]  
  22. })  
  23. export class AppModule {}  
Open app.component.html from path ‘ng-app/src/app’. Add code to file. Here we are showing chat window for chat history and text area for user to send message. User will add text to text area and press enter to send a message. Smiley button is for sending a smiley.
  1. <div style="width:33%;margin-left:auto;margin-right:auto" class="alert alert-info">  
  2.     <div> Welcome to chat application created by <img width="150" src="AkshayLetters.png"> your network id: {{socketId}} </div>  
  3.     <div class="alert alert-success" style="height:300px;overflow-y:auto" #chatwindow>  
  4.         <div *ngFor="let message of messages" class="alert" [ngClass]="(socketId==message.from)? 'sent-chat alert-info':'received-chat alert-warning'">  
  5.             <div *ngIf="message.text==':)'"><span class="badge" *ngIf="socketId!=message.from">{{message.from}}</span> <i class="fa fa-smile-o" aria-hidden="true"></i></div>  
  6.             <div *ngIf="message.text!=':)'"><span class="badge" *ngIf="socketId!=message.from">{{message.from}}</span> {{message.text}}</div>  
  7.         </div>  
  8.     </div>  
  9.     <div class="alert alert-success "> <textarea rows="4 " [(ngModel)]="message " (keydown.enter)="sendMessage();false;" style="width:100% "></textarea> <button (click)="sendSmily() " class="btn btn-default" style="margin-left:auto; "><i class="fa fa-smile-o" aria-hidden="true"></i></button> </div>  
  10. </div>  
We are ready with our code. Let’s build an Angular application by executing ‘ng build’ command. Then run ‘node starter.js’ command to start our application.

Open two browsers and hit ‘http://localhost:9696’ from both the browsers. And start chatting…

In the next article Build Chat Application On MEA2N Stack – Part Two, we will integrate MongoDB Atlas with our chat application for chat history. Until then, keep chatting.