WebSocket is a web communication protocol that allows two-way communication between a client and a server.

What makes that technology appealing is that unlike regular TCP sockets, WebSockets use the same port as the HTTP protocol, which is port 80.

This means that when using WebSockets you don’t have to worry about firewalls blocking that port and preventing your data to flow between client and server.

The technology has been around for a while, long enough to enjoy excellent support across all browsers according to caniuse.com:

PS: but, keep in mind that … some older browsers may not support WebSockets. 

WebSockets in Angular

Angular utilizes RxJS which is essentially a javascript implementation of reactive extensions. This is a library for composing asynchronous and event-based programs using observable sequences and is perfect for working with WebSockets.

This is actually almost too easy. You just have to import the webSocket function from RxJs, call it with the URL of your WebSocket, and… done!

import {webSocket, WebSocketSubject} from 'rxjs/webSocket';
myWebSocket: WebSocketSubject = webSocket('ws://localhost:8000');

You now have an RxJs subject that you can subscribe to in order to receive some data:

myWebSocket.asObservable().subscribe(dataFromServer => //...);

And if you want to send data to the server, simply use the next method of your subject:

myWebSocket.next({message: 'some message'});

Also note that when you subscribe to a WebSocket subject, you can register callbacks to be notified when an error happens or when the connection is closed, just like with a regular observable:

myWebSocket.subscribe(    
   msg => console.log('message received: ' + msg), 
   // Called whenever there is a message from the server    
   err => console.log(err), 
   // Called if WebSocket API signals some kind of error    
   () => console.log('complete') 
   // Called when connection is closed (for whatever reason)  
);

Example

An example of this could be in a real-time chat application. Say we have 3 people connected to our chat application and one of them sends a message. If we want to do something in our application whenever we receive a message then we can simply subscribe to a ‘new-message’ event and handle the event whenever it is triggered.

PS: The best way to implement WebSockets in our angular applications would be to encapsulate our WebSockets and events in a service and then call that service in whatever components we wish to interact with a websocket.

  • Creating our Websocket Service

To get us started we’ll be creating a very simple service that will connect to any given URL and return an RxJS subject that we can subscribe to in other services/components in order to listen for any incoming messages from the connected socket.

ng g service websocket

We’ll need to import * from the rxjs library at the top of our new service. This will allow us to create the subject that will both observe and be observable. This essentially means our subject will watch our websocket for any incoming messages and will broadcast these messages to any components that happen to be subscribing to this service.

import { Injectable } from "@angular/core";
import * as Rx from "rxjs/Rx";

@Injectable()
export class WebsocketService {
  constructor() {}

  private subject: Rx.Subject<MessageEvent>;

  public connect(url): Rx.Subject<MessageEvent> {
    if (!this.subject) {
      this.subject = this.create(url);
      console.log("Successfully connected: " + url);
    }
    return this.subject;
  }

  private create(url): Rx.Subject<MessageEvent> {
    let ws = new WebSocket(url);

    let observable = Rx.Observable.create((obs: Rx.Observer<MessageEvent>) => {
      ws.onmessage = obs.next.bind(obs);
      ws.onerror = obs.error.bind(obs);
      ws.onclose = obs.complete.bind(obs);
      return ws.close.bind(ws);
    });
    let observer = {
      next: (data: Object) => {
        if (ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify(data));
        }
      }
    };
    return Rx.Subject.create(observer, observable);
  }
}

Next what we want to do is to create a second service that will interface with our websockets and will act as a type of adapter which will adapt the output from our websocket into a form that we can easily work with in the frontend. Again create this service using the angular-cli:

ng g service chat

This should create a chat.service.ts within your root directory. In this file we are going to do something like so:

import { Injectable } from "@angular/core";
import { Observable, Subject } from "rxjs/Rx";
import { WebsocketService } from "./websocket.service";

const CHAT_URL = "ws://echo.websocket.org/";

export interface Message {
  author: string;
  message: string;
}

@Injectable()
export class ChatService {
  public messages: Subject<Message>;

  constructor(wsService: WebsocketService) {
    this.messages = <Subject<Message>>wsService.connect(CHAT_URL).map(
      (response: MessageEvent): Message => {
        let data = JSON.parse(response.data);
        return {
          author: data.author,
          message: data.message
        };
      }
    );
  }
}
  • Updating our App Component

Finally we’ll want to update our app.component.ts file so that it imports our newly created chat service and allows us to push messages to this websocket:

import { Component } from "@angular/core";
import { WebsocketService } from "./websocket.service";
import { ChatService } from "./chat.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  providers: [WebsocketService, ChatService]
})
export class AppComponent {
  constructor(private chatService: ChatService) {
    chatService.messages.subscribe(msg => {
      console.log("Response from websocket: " + msg);
    });
  }

  private message = {
    author: "tutorialedge",
    message: "this is a test message"
  };

  sendMsg() {
    console.log("new message from client to websocket: ", this.message);
    this.chatService.messages.next(this.message);
    this.message.message = "";
  }
}

Finally we’ll need to update our html page for our app component so that we can actually use the sendMsg() function that we defined in our component file:

<!-- app.component.html -->
<h1>
  Angular 2 WebSockets Tutorial
</h1>

<button (click)="sendMsg()">Send Message</button>

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist

Leave a Reply

Your email address will not be published. Required fields are marked *