DEV Community

Cover image for Real-Time Applications Node.js and Angular with Socket.IO
Kafeel Ahmad (kaf shekh)
Kafeel Ahmad (kaf shekh)

Posted on

Real-Time Applications Node.js and Angular with Socket.IO

In today’s fast-paced digital world, real-time communication has become a crucial aspect of modern web applications. Whether it’s live chat, notifications, or real-time data updates, providing instant feedback to users enhances the overall user experience. In this blog post, we will explore how to implement real-time communication using Socket.IO with Angular and Node.js. By the end of this tutorial, you will have a solid understanding of how to set up a real-time application that can handle client-server communication efficiently.

What is Socket.IO?
Socket.IO is a JavaScript library that enables real-time, bidirectional, and event-based communication between web clients and servers. It builds on top of the WebSocket protocol, providing additional features like automatic reconnection, multiplexing, and error handling, which make it a powerful tool for real-time applications.

WebSockets vs. Socket.IO:
WebSockets: A protocol that enables low-latency, full-duplex communication channels over a single TCP connection.
Socket.IO: An abstraction layer on top of WebSockets that provides additional functionality, making it easier to implement real-time features.
Project Initialization
To get started, we’ll set up a project structure with separate client and server directories.

Creating Directories:

client: This will contain the Angular application.
server: This will contain the Node.js application.
Initializing Angular Application:

ng new client

cd client

npm install socket.io-client
Enter fullscreen mode Exit fullscreen mode

Initializing Node.js Application:

mkdir server

cd server

npm init -y

npm install express cors socket.io

npm install --save-dev nodemon
Enter fullscreen mode Exit fullscreen mode

Setting Up nodemon:

Update the package.json file to use nodemon for automatically restarting the server on file changes.

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

Setting Up Socket.IO on the Client with Observables
Integrating Socket.IO-client with Angular using Observables:

Create an Angular service to manage Socket.IO connections and use observables to handle events.

// src/app/services/socket.service.ts
import { Injectable } from '@angular/core';
import { io, Socket } from 'socket.io-client';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class SocketService {
  private socket: Socket;

  constructor() {
    this.socket = io('http://localhost:3000');
  }

  emit(event: string, data: any) {
    this.socket.emit(event, data);
  }

  on(event: string): Observable<any> {
    return new Observable((observer) => {
      this.socket.on(event, (data) => {
        observer.next(data);
      });

      // Handle cleanup
      return () => {
        this.socket.off(event);
      };
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Establishing a Connection:

Use the SocketService in your components to establish a connection and subscribe to events.

// src/app/app.component.ts
import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { SocketService } from './services/socket.service';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  standalone: true,
  imports: [FormsModule],
})
export class AppComponent implements OnDestroy {
  private messageSubscription: Subscription;
  messages: string[] = [];
  newMessage: string = '';

  constructor(private socketService: SocketService) {
    this.messageSubscription = this.socketService
      .on('message')
      .subscribe((data) => {
        this.messages.push(data.text);
      });
  }

  sendMessage() {
    this.socketService.emit('message', { text: this.newMessage });
    this.newMessage = '';
  }

  ngOnDestroy() {
    this.messageSubscription.unsubscribe();
  }
}
Enter fullscreen mode Exit fullscreen mode

Modifying the HTML Template:

Update app.component.html to include an input field for sending messages and a display area for received messages.

<!-- src/app/app.component.html -->
<div>
  <h1>Real-Time Chat</h1>
  <div>
    <input [(ngModel)]="newMessage" placeholder="Enter your message" />
    <button (click)="sendMessage()">Send</button>
  </div>
  <div>
    <h2>Messages:</h2>
    <ul>
      @for ( message of messages; track $index) {
      <li>{{ message }}</li>
      }
    </ul>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Setting Up Socket.IO on the Server
Setting Up an Express.js Server:

// server/index.js
const express = require("express");
const http = require("http").createServer();
const io = require("socket.io")(http, {
  cors: {
    origin: "*",
  },
});
const cors = require("cors");

const app = express();
const port = 3000;

// Enable CORS for all requests
app.use(cors());

// Define a route handler for the root path
app.get("/", (req, res) => {
  res.send("Hello, world!");
});

io.on("connection", (socket) => {
  console.log("New client connected");
  socket.on("disconnect", () => {
    console.log("Client disconnected");
  });
});

// Start the server
http.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Handling Client Connections and Disconnections:

io.on('connection', (socket) => {
  console.log('New client connected');

  socket.on('message', (data) => {
    console.log('Received message:', data);
    io.emit('message', data); // Broadcasting the message
  });

  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});
Enter fullscreen mode Exit fullscreen mode

Emitting Events
Emitting events is a fundamental part of Socket.IO’s event-driven architecture. Here’s how you can emit events from the client to the server and handle them on the server.

Client Side:

  sendMessage() {
    this.socketService.emit('message', { text: this.newMessage });
  }
Enter fullscreen mode Exit fullscreen mode

Server Side:

socket.on('message', (data) => {
console.log('Received message:', data);
});
Broadcasting Events
Broadcasting allows the server to send messages to all connected clients. This is useful for real-time updates like chat messages or notifications.

Server Side:

socket.on('message', (data) => {
  console.log('Received message:', data);
  io.emit('message', data); // Broadcasting the message to all clients
});
Enter fullscreen mode Exit fullscreen mode

Client Sode:

constructor(private socketService: SocketService) {
this.messageSubscription = this.socketService.on('message').subscribe((data) => {
this.messages.push(data.text);
});
}
Handling Disconnections
Handling disconnections ensures that your application can gracefully manage client departures, maintaining the integrity of real-time interactions.

Server Side:

socket.on('disconnect', () => {
  console.log('Client disconnected');
});
Enter fullscreen mode Exit fullscreen mode

Client Side:

You don’t need additional code on the client side for disconnections, as Socket.IO handles this automatically.

Conclusion
In this blog post, we covered the basics of implementing real-time communication using Socket.IO with Angular and Node.js. We discussed project initialization, setting up Socket.IO on both the client and server, emitting and broadcasting events, and handling disconnections. Real-time communication is a powerful feature that can significantly enhance user experience, and Socket.IO makes it easy to implement.

By following this guide, you should now have a working real-time application. Feel free to explore further features of Socket.IO and experiment with more complex use cases

Top comments (0)