Post
Chat Application with Angular and Socket.IO
Introduction
We will use RxJS, Angular, express (Node.js) & Socket.IO to make a chat application. We will get to see how useful RxJS can be in this scenario. For the purpose of making things smooth and easy we will be using Angular CLI to generate basic client structure and get us a boilerplate for simplest working Angular application. On the back-end we will use Node.js with express and Socket.IO. Reasoning behind this is that Socket.IO is very easy to set up and work with. Furthermore, it provides both server and client side libraries. Socket.IO primarily uses WebSocket protocol to enable real-time bidirectional communication.
If you wanna jump directly to part where we use RxJS to handle the chat messages click here.
Lets get started!
Socket.IO server setup
If you do not have Angular CLI installed you can install it quite easily:
npm i -g @angular/cli
Set up folder structure
To keep things clean we are gonna create new rxjs-chat folder for our little project. It should serve as root folder for Angular and Socket.IO apps.
Lets create a basic Angular app using Angular CLI. In our project folder launch your favorite terminal and run the following command:
ng new rxjs-chat
Give it a bit of time. After its done creating basic structure and installing npm packages we will rename newly created Angular project folder to client. After that, in the same root folder create folder server for our Socket.IO server. Now we have two folders inside our rxjs-chat folder:
- client - Angular client app
- server - soon to be Node’s Socket.IO server
Installing local packages
In the server folder we will generate package.json file by running the following command:
npm init -y
After that we will install our dependencies and save them to package.json:
npm install express socket.io --save
In the same folder we will create index.js file for our server app. Content of the file should be as following:
https://gist.github.com/Ibro/69fce97acd7e753713265bd2048872ee
We create an instance of express and store it into app variable. After that we create server with http module. Then we pass express to http.Server() method. Express will serve as the handler for requests to our server. In return we get the instance of server which we store in server variable.
In the next two lines of code we bind the socket.IO with our http server:
let socketIO = require('socket.io');
let io = socketIO(server);
After that we listen for connection event of socket.IO and we log once a user has established a connection with the server. Finally we start the server and listen on given port, in our case it is port 3000.
Lets actually start our server by running the following in server folder:
node index.js
Consequently you should get the following message: “started on port: 3000”.
Connecting to Socket.IO
We have a server running on port 3000. Now it is time to see how we can connect to the server from our Angular app. For this we will need to install Socket.IO client library. We will run the following command in our client folder:
npm install socket.io-client --save
While we are at it lets run the Angular app via Angular CLI:
ng serve -o
Now we got our app running. We can see that our default browser just opened a new tab pointing at localhost. That is why we used -o argument to open the browser.
Creating service for communication with server
I am gonna name it chat.service.ts app.chat.service.ts and place it inside of src folder. Service is gonna be as simple as possible for now:
https://gist.github.com/Ibro/e1e219b7102d06455a0cff0df2e62657
Adding the service to module providers
Also, lets add our ChatService to providers list inside of AppModule in app.module.ts file:
https://gist.github.com/Ibro/f842beab3833fe3c16ae3df08ce6f83c
Injecting the service in our component
Finally, we are going to import and use the service inside of our app.component.ts file:
import { ChatService } from './app.chat.service';
And we will inject the ChatService in our constructor:
constructor(chatService: ChatService) { }
As a result we have the following file:
https://gist.github.com/Ibro/5868bebd764111bcb058108c8e1a80bc
If everything went as expected after saving the changes you should see the ‘user connected’ message in the terminal where you started node app:
$ node index.jsstarted on port: 3000user connected
Hence, we can say we finally managed to connect to our Socket IO server. Now it is time to actually send some data via Socket IO events.
Sending a message to Socket.IO
Time to enhance our so far simple ChatService with an option to send a message to server:
https://gist.github.com/Ibro/f9da06e580b0d96b2093e32764a61a26
For this to work we have to use sendMessage() from our AppComponent:
https://gist.github.com/Ibro/96c96c3146fd18ad10e2f2971d0f145c
Finally, lets provide user with a simple text input and a button so he can send a message:
https://gist.github.com/Ibro/d24a1ca48cce394e4ce33f97df755cd4
For this all to work we have to listen on the server for ’new-message’ event that we emitted from ChatService:
socket.on('new-message', (message) => {
console.log(message);
});
Now our index.js looks like this:
https://gist.github.com/Ibro/9756866792271b0bc12b54d61caa6b9f
If you want to play around with the code you can find it at my GitHub repo - rxjs-chat.
Communicating with other users
For our message to get broadcasted to other users all we have to do is change the console.log(message) inside of our ’new-message’ event callback to io.emit(message):
https://gist.github.com/Ibro/525748f54e0756195f43c6e35f1687c2
And what does io.emit() do? In simple words it sends an event to everyone connected to the server.
Lets communicate with our server via ChatService. We will add a new method to our service for this purpose - getMessages. It will return an Observable that we will create with Observable.create() method. Every time socket receives a new messages we will use observer.next() to forward it to observers.
https://gist.github.com/Ibro/a535c10a348370650d184079a957f46c
After that we subscribe to this Observable from our AppComponent:
https://gist.github.com/Ibro/12a9b1444f2401aa4d3a87f3fc23342a
We created a new messages array where we will store messages received from server. We will have to show those messages in our template. That is perfect use case for ngFor:
https://gist.github.com/Ibro/9da535203d93ddb6d0e47ff8aae3cb9d
Summary
Now we have a simple chat application working. Users do not have usernames and we do not have chat-rooms, but we will talk about that in one of future posts.
In the next post we will see how we can handle chat messages with RxJS.