Angular + WebSocket + Node.js Express = RxJS WebSocketSubject ❤️

Angular + WebSocket + Node.js Express = RxJS WebSocketSubject ❤️

Angular + WebSocket + Node.js Express = RxJS WebSocketSubject

Given the wide interest in my previous article on WebSocket, Node and Express (thanks to everyone 😅) I created a simple Angular client that allows you to communicate with the server made in the previous tutorial (PS: I also updated the libraries related to the server component 🎉).

This mini-project (source code here and working DEMO here**🎠 **— try to open two or more browser windows and play with the broadcast button) can be summarized in the following code snippet:

import { Component, ViewChild, ElementRef, OnInit, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { WebSocketSubject } from 'rxjs/observable/dom/WebSocketSubject';

export class Message {
    constructor(
        public sender: string,
        public content: string,
        public isBroadcast = false,
    ) { }
}

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {

    //...

    private socket$: WebSocketSubject<Message>;

    constructor() {
        this.socket$ = WebSocketSubject.create('ws://localhost:8999');

        this.socket$
            .subscribe(
            (message) => this.serverMessages.push(message) && this.scroll(),
            (err) => console.error(err),
            () => console.warn('Completed!')
            );
    }

    //...
}

websocket-node-express-component.ts hosted with ❤ by GitHub

As you can see, we are initializing a WebSocketSubject and specifying the type of object we intend to obtain from the server (in this case, simply a Message).

Obviously, the definition of the obtained object must conform to what is communicated by the server (for this reason I always suggest working with shared objects inside your repo— in this case we are facilitated by using both server and client side of the same language, Typescript 😎).

Coming back to the definition of the WebSocketSubject we can say that this is a very useful tool of RxJS library that represents a wrapper around the w3c-compatible WebSocket object provided by the browser.

It is therefore sufficient to subscribe and define the actions that our code must perform:

The rest of the client shows a little graphic trick to make the scroll of the interface a little bit smooth without using any additional library 😏. If you want, checkout the animation algorithm at 60fps with the calculation of the remaining scroll.

You could get the same thing with the CSS only but I preferred to get my hands dirty to refresh the characteristics of the @ViewChild and ElementRef).

 private getDiff(): number {
        const nativeElement = this.viewer.nativeElement;
        return nativeElement.scrollHeight - (nativeElement.scrollTop + nativeElement.clientHeight);
    }

    private scrollToBottom(t = 1, b = 0): void {
        if (b < 1) {
            b = this.getDiff();
        }
        if (b > 0 && t <= 120) {
            setTimeout(() => {
                const diff = this.easeInOutSin(t / 120) * this.getDiff();
                this.viewer.nativeElement.scrollTop += diff;
                this.scrollToBottom(++t, b);
            }, 1 / 60);
        }
    }

    private easeInOutSin(t): number {
        return (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;
}

websocket-node-express-component-scroll.ts hosted with ❤ by GitHub

The same applies to the calculation of the badge color based on the initials typed by the user ;)

 public getSenderInitials(sender: string): string {
        return sender && sender.substring(0, 2).toLocaleUpperCase();
    }

    private getSenderColor(sender: string): string {
        const alpha = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZ';
        const initials = this.getSenderInitials(sender);
        const value = Math.ceil((alpha.indexOf(initials[0]) + alpha.indexOf(initials[1])) * 255 * 255 * 255 / 70);
        return '#' + value.toString(16).padEnd(6, '0');
}

websocket-node-express-component-initials-color.ts hosted with ❤ by GitHub

For demonstration purposes only, within the server I added a 1000ms timeout to make the server response more “real” in case you want to try the compiled code locally.


Conclusions

In just a few steps, we’ve created an Angular client using RxJS WebSocketSubject: soon we can go deep in catching errors and reconnection policies, but this will come in another story 🎉


Learn More

The Complete Node.js Developer Course (3rd Edition)

NodeJS - The Complete Guide (incl. MVC, REST APIs, GraphQL)

Node.js: The Complete Guide to Build RESTful APIs (2018)

Angular 7 (formerly Angular 2) - The Complete Guide

Angular & NodeJS - The MEAN Stack Guide

How to use Node.js, Express.js and Multer Restful API for Image Uploader?

Node.js - Express Persistent Session Store with PostgreSQL + Sequelize

Secure Node.js, Express.js and PostgreSQL API using Passport.js

Fullstack Vue App with Node, Express and MongoDB

Build a Simple Web App with Express, Angular, and GraphQL

Originally published by Jonny Fox at https://medium.com