+ - 0:00:00
Notes for current slide
Notes for next slide

WebSocket

Learn how to connect and react to events from a WebSocket in your Angular application.

This material is part of the mobile development course for Media Engineering.

Recommended reading

1 / 14

WebSocket API

WebSocket

Using WebSocket on the front-end is supported by most - if not all - browsers since before 2011, thanks to a native HTML5 API.

Since there is a native WebSocket API, you technically don't need to install any npm packages to use it in your app. Those packages simply provides more high level implementations.

In this subject, we will build a very minimal Angular Service to connect, listen and send messages to a backend offering WebSocket capabilities, based on the documentation for the WebSocket API.

2 / 14

WebSocket

WebSocket

The WebSocket class is the main interface to the WebSocket API.

To connect to an existing WebSocket server, you simply need to instantiate a new WebSocket object, providing the constructor with the WebSocket URL:

const ws = new WebSocket('ws://echo.websocket.org');

A WebSocket object can be in one of four states, defined as static constants of the WebSocket class:

  • CONNECTING - The connection is not yet opened
  • OPEN - The connection is opened and messages can be exchanged
  • CLOSING - The connection is being closed
  • CLOSED - The connection is closed and messages can no longer be exchanged

To check the state in which a WebSocket instance currently is, use its readyState property:

if (ws.readyState === WebSocket.OPEN) {
// Do something only if the connection is open
}
3 / 14

Angular WebSocket Service

WebSocket > WebSocket

We can create a new Angular service that will manage this WebSocket object and proxy it to the components in which it is injected.

Create a new file, e.g. websocket.service.ts with the following code:

import { Injectable } from '@angular/core';
import { Observable, Observer, ReplaySubject } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
const WS_SERVER_URL = 'ws://echo.websocket.org';
@Injectable({ providedIn: 'root' })
export class WebsocketService {
// A ReplaySubject will emit its X latest values (1 in this case) each time
// its 'subscribe()' method is called
private ws$ = new ReplaySubject<WebSocket>(1);
constructor() {
const socket = new WebSocket(WS_SERVER_URL);
socket.onopen = () => {
console.log('Successfully connected to the WebSocket at', WS_SERVER_URL);
// When the connection is done, emit the WebSocket instance
this.ws$.next(socket);
};
}
}
4 / 14

Use the service

WebSocket > WebSocket

To use the service, simply inject it in one of your components:

// Other imports...
import { WebsocketService } from 'path/to/websocket.service';
@Component({ /* ... */ })
export class ExampleComponent {
// ...
constructor(private wsService: WebsocketService) {
// ...
}
// ...
}

Injecting the service is enough to connect to the WebSocket, since we do this in the Service constructor.

5 / 14

Listening to messages

WebSocket

Several of a WebSocket object's properties can be set to react to specific events such as:

Each of these porperties expect a callback function that will be called when the corresponding event occurs:

We already did this in the Angular Service to react to a successfull connection

// Log all messages
ws.onmessage = message => console.log(message);
6 / 14

Add listening capabilities to the Angular Service

WebSocket > Listening to messages

As said in previous subjects, Angular 2+ heavily uses rxjs' Observable, which are very well suited to handle WebSocket messages.

Remember that Observable allow us to subscribe to a particular stream of events in order to do something each time on of those events is fired, until the stream is closed.

From the the front-end point of view, a WebSocket connection is pretty much the same thing: a stream of messages emitted until the connection is closed.

It would thus be quite natural that our Angular WebSocketService exposes an Observable that emits a new value each time a message is broadcasted on the WebSocket connection.

The WebSocket API define such a message with the MessageEvent interface.

Let's create a new listen() method on our WebSocketService that returns an Observable<any> (where any is the data of the message).

7 / 14

listen() method

WebSocket > Listening to messages > Add listening capabilities to the Angular Service

Add this method to the service in websocket.service.ts:

import { Injectable } from '@angular/core';
import { Observable, Observer, ReplaySubject } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class WebsocketService {
// ...
public listen<T = any>(): Observable<T> {
// Only listen when the connection is opened
return this.ws$.pipe(
// Make an observable out of the websocket stream
switchMap(socket =>
new Observable((subscriber: Observer<MessageEvent<T>>) => {
// When a new message is received, the Observable will emit this message
socket.onmessage = message => subscriber.next(message);
// When a websocket error occurs, the Observable will emit a new error
socket.onerror = error => subscriber.error(error);
// When the websocket closes, the observable completes
socket.onclose = () => subscriber.complete();
// Function that will be called if the user manually unsubscribe
return () => socket.close();
})
),
// When a message is emitted, change the value to the message content
map((event: MessageEvent<T>) => event.data)
);
}
}
8 / 14

Listen on the component

WebSocket > Listening to messages > Add listening capabilities to the Angular Service

To listen to messages on the WebSocket instance in your component, subscribe to its listen() method:

// Imports...
@Component({ /* ... */ })
export class ExampleComponent {
// ...
constructor(private wsService: WebsocketService) {
// ...
this.wsService
.listen()
.subscribe(message => {
// Do something when a message is received
});
// ...
}
// ...
}
9 / 14

Type the message data

WebSocket > Listening to messages > Add listening capabilities to the Angular Service

By default, the data that you can access in the listen() subscribe callback is type with any, since the method does not know the structure of the received message data. You can tell what type of data you expect to receive to the listen() to have proper typings.

Let's suppose we designed our WebSocket API so that all our messages have a type and content property. We could define it in our app:

export type WsMessage = {
type: string;
content: any;
};

Now, when calling the listen() method, we can tell it that we expect to receive this type of data in our messages:

this.wsService.listen<WsMessage>().subscribe(message => {
// message is now of type WsMessage.
});
10 / 14

Send messages

WebSocket > Listening to messages

Sending a message is very easy, once connected to a WebSocket.

Simply call the send() method of a WebSocket instance, passing it the data you want to send (usually some JSON formatted value):

const data = {
foo: 'bar'
};
ws.send(JSON.stringify(data));

Note that you could also send binary data (e.g. files) through this method.

11 / 14

Sending messages on the service

WebSocket > Listening to messages > Send messages

To make our WebSocketService capable of sending messages, we will create a new send() method that takes an argument, and calls the WebSocket.send() method.

// Imports
const WS_SERVER_URL = 'ws://echo.websocket.org';
@Injectable({ providedIn: 'root' })
export class WebsocketService {
private ws: WebSocket;
// ...
public send(data: unknown): void {
this.ws$.subscribe(socket => {
socket.send(JSON.stringify(data));
});
}
}

Note that the data param is typed as unknown, because the send() method doesn't care (nor know) what type of data you want to send.

12 / 14

Sending messages from the component

WebSocket > Listening to messages > Send messages

To send some message from the component, simply call our WebSocketService's send() method with a serializable value, e.g. a binded input value:

<input type="text" name="msg" id="msg" [(ngModel)]="message" />
<button (click)="sendMessage()" >Envoyer</button>
// Imports...
@Component({ /* ... */ })
export class ExampleComponent {
message: string;
// ...
sendMessage() {
this.wsService.send({ msg: this.message });
}
// ...
}
13 / 14

Next steps

WebSocket

As annouced, we've built a very simple Angular Service to manage websocket connection, and sending/receiving messages.

Some enhancment could be implemented, depending on your needs, such as:

  • Sending binary data with our service's send() method,
  • Keeping and retrieving several websocket connections in the service,
  • ...

The complete Angular WebSocketService can be found here

14 / 14

WebSocket API

WebSocket

Using WebSocket on the front-end is supported by most - if not all - browsers since before 2011, thanks to a native HTML5 API.

Since there is a native WebSocket API, you technically don't need to install any npm packages to use it in your app. Those packages simply provides more high level implementations.

In this subject, we will build a very minimal Angular Service to connect, listen and send messages to a backend offering WebSocket capabilities, based on the documentation for the WebSocket API.

2 / 14
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow