I this article, you’ll learn how to create an Angular client using RxJS WebSocketSubject, WebSocket, Node.js and Express.js

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:

  • upon obtaining new values, the new message will be added to an array, providing the scroll of the interface in order to display it properly
  • receiving an error it will be displayed in the console
  • at the end of the stream a warning will be presented in the console

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 🎉

#angular #node-js #express #web-development

Angular + WebSocket + Node.js Express = RxJS WebSocketSubject ❤️
4 Likes331.00 GEEK