angulartypescriptrxjsangular12angular13

Rxjs subscribes only once, in 1 component, not same time diff components in angular 14


Rxjs subscribes only once, in 1 component, not the same time diff components in angular 14.

Requirements

I am building a notification service, when any customer, submits any case, it's assigned to a support team, and I want to notify customers and the support team at the same time, or 1-2 sec duration, I am using the WebSockets here.

Code - Notification.service.ts:

import { Injectable } from '@angular/core';
import { Subject, Observable } from "rxjs";
import { Notification, NotificationType } from "../models/notification.model";

@Injectable()
export class NotificationService {

  private _subject = new Subject<Notification>();
  private _idx = 0;

  constructor() { }

  getObservable(): Observable<Notification> {
    return this._subject.asObservable();
  }

  info(title: string, message: string, timeout = 3000) {
    this._subject.next(new Notification(this._idx++, NotificationType.info, title, message, timeout));
  }

  success(title: string, message: string, timeout = 3000) {
    this._subject.next(new Notification(this._idx++, NotificationType.success, title, message, timeout));
  }

  warning(title: string, message: string, timeout = 3000) {
    this._subject.next(new Notification(this._idx++, NotificationType.warning, title, message, timeout));
  }

  error(title: string, message: string, timeout = 0) {
    this._subject.next(new Notification(this._idx++, NotificationType.error, title, message, timeout));
  }

}

In the Notification component, I subscribe like this:

notification.ts

import { debounceTime, Subscription } from "rxjs";
private _subscription: Subscription;
constructor(private _notificationSvc: NotificationService) { }

    this._subscription = this._notificationSvc.getObservable().pipe(debounceTime(1000)).subscribe((notification) => {
            console.log("I am notification called: -", notification);
            this._addNotification(notification)
        });

Websockets code:

import { Injectable } from '@angular/core';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
import { Subject, Observable, BehaviorSubject, pipe, mergeMap } from "rxjs";
import { environment } from '../../environments/environment';
import { SharedservicesService }    from './sharedservices.service';
import { NotificationService }      from './notification.service';
@Injectable()
export class WebSocketService {
  public subject: WebSocketSubject<any>;

  currentUser: any;
  params:any;
 
  constructor(private shared: SharedservicesService, private notificationService: NotificationService) {
    this.getRequestIds();
  }

  public getRequestIds() {
    this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
    if(this.currentUser) {
        const data = {
            key: this.currentUser["cognito:username"],
        }
        this.shared.getRequestIds(data).subscribe({
            next: async(response) => {
              const responseData = JSON.parse(JSON.stringify(response));
              this.connect(responseData.result);
            },
            error: (error) => {
              console.log(error);
            }
        })
    }
  }

  public connect(requestId) {
    this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
    this.params = "?userId="+this.currentUser["cognito:username"]+"&userEmail="+this.currentUser["email"]+"&userName="+this.currentUser["custom:name"]+"&role="+this.currentUser["custom:role"]+"&requestids="+requestId
    this.subject = webSocket({
      url: environment.websocketUrlClient+""+this.params,
      deserializer: ({ data }) => {
        return new Promise((res, rej) => {
          res(data);
        });
      },
      openObserver: {
        next: () => {
          console.log('connecion ok');
        },
      },
      closeObserver: {
        next: () => {
          console.log('disconnect ok');
          this.getRequestIds();
        },
      },
    });
    this.subject.subscribe();
  }

  public send(msg) {
    console.log('Send Message:', msg);
    this.subject.next(msg);
  }

  public disconnect() {
    this.subject.complete();
  }

  public receiveMessage() {
    this.subject.subscribe(
      (msg) => {
        if(msg.__zone_symbol__value != "") {
          
          const data = JSON.parse(msg.__zone_symbol__value);
          console.log('message received: ', data);

          // Problem here ---- 
          // Login 2 diff browser, Customer and support team, When send message, to support team, customer getting notification but support team are not, because support team are not in the same browser, I am using WebSocket to send the message

          if(data.sendRoomToAssignedBusinessAnalysts) { // when first Business Analyst is added
            console.log("Title:", data.title);
            console.log("Body:", data.body);
            this.notificationService.success(data.title, data.body)
            
          }
        }
      },
    );
  }
}

There are no errors.

Problem

I am getting notifications for the customer, not for the support team member. Because the Rxjs subject, subscribes only once, in 1 component, not same time diff components.

Youtube link (explained about the problem): https://www.youtube.com/watch?v=R5dhCUC3x5s

Github repo: https://github.com/codeztech-atique/angular-websockets-testing-api

Stackblitz: https://stackblitz.com/edit/angular-ivy-eiqr8u

Any help would be appreciated. I am new to this. Might be something I am missing here, Let me know, what could be done.


Solution

  • Your problem is very simple, there is no problem with RxJS or the subscription.

    The problem is that you have <app-notification></app-notification> inside customer.component.html but inside support.component.html is missing. Therefore the notification won't be displayed.

    to solve your problem you have to add <app-notification></app-notification>to support.component.html.

    Then you have <app-notification></app-notification> in both components. This works but a better solution would be to move <app-notification></app-notification> to app.component.html, so you have the component only once and it works everywhere, even if you add more pages.