Change detection is not triggered when using Behaviorsubject

1k Views Asked by At

I have two sibling components each one communicates and send data through Behaviorsubject which is in service. Component A is subscribe inside ngOnInit for data coming from component B.

Component B Listen for message coming from websoket , when the message arrives I`m triggering method which updates the Behaviorsubject value.So when the new date arrives from component B , component A must shown confirmation modal but the modal is not showning because angular change detection is not being triggered even if I use Object.assign().

Where am I wrong ?

Here is my code:

product.service.ts

    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs';
    
    
    @Injectable({
      providedIn: 'root'
    })
    
    export class ProductService {
    
      subjectProps: any = {
        showErrorModal: undefined,
        showSuccessfullyModal: undefined,
      };
    
      _subject$ = new BehaviorSubject(this.subjectProps);
      event = this._subject$.asObservable();
    
      constructor() { }
    
      updateSubjectProps(data: any) {
        this._subject$.next(data);
      };
    }

successfully-modal.component.ts

 import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
    import { Subscription } from 'rxjs';
    import { ProductService } from '../../../services/product-catalogue.service';
    
    @Component({
      selector: 'successfully-modal',
      templateUrl: './successfully-modal.component.html',
      styleUrls: ['./successfully-modal.component.scss']
    })
    
    export class ImportCompletedSuccessfullyModalComponent implements OnInit, OnDestroy {
      showErrorModal: boolean = false;
      showSuccessfullyModal: boolean = false;
    
      productSubscription: Subscription
    
      constructor(private productService: ProductService) { }
    
      ngOnInit(): void {
        this.productSubscription = this.productService.event.subscribe(data => {
          if (data) {
            // Here I need to open successflully confirmation modal
            this.showSuccessfullyModal = data.showSuccessfullyModal;
          }
        });
      }
    
      ngOnDestroy(): void {
        if (this.productSubscription) {
          this.productSubscription.unsubscribe();
        }
      }
    
    }

products.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';
import { ProductService } from './services/product-catalogue.service';
import { Subscription } from 'rxjs';
import { webSocketListener } from '../../../event-bus';


@Component({
  selector: 'products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.scss']
})

export class MigrationToolComponent implements OnInit, OnDestroy {
  subjectProps: any;
  productSubscription: Subscription
  isLoading: boolean;
  products: any[] = [];

  constructor(private productService: ProductService) { }

  ngOnInit(): void {
    this.fetchProducts();

    this.productSubscription = this.productService.event.subscribe(data => {
      this.subjectProps = data;
    });

    webSocketListener.on((message: any) => {
      this.checkProductStatus(message);
    });
  }

  fetchProducts(): void {
    this.isLoading = true;
    this.productService.getProducts().subscribe(res => {
      this.isLoading = false;
      this.products = res.products;
    }),
      error => {
        this.isLoading = false;
        console.log(error);
      }
  }

  checkProductStatus(message: string) {
    let subjectProps = Object.assign({}, this.subjectProps);

    if (message === 'failed') {
      subjectProps.showErrorModal = true;
      subjectProps.showSuccessfullyModal = false;
    }

    if (message === 'success') {
      subjectProps.showSuccessfullyModal = true;
      subjectProps.showErrorModal = false;
    }

    this.productService.updateSubjectProps(subjectProps);
    this.fetchProducts();
  }

  ngOnDestroy(): void {
    if (this.productSubscription) {
      this.productSubscription.unsubscribe();
    }
  }

}
1

There are 1 best solutions below

1
On BEST ANSWER

This is related to the webSocketListener (probably) works outside of angular. You should call checkProductStatus function in angular, you can use NgZone service this.

import { Component, OnDestroy, OnInit, NgZone } from '@angular/core';
import { ProductService } from './services/product-catalogue.service';
import { Subscription } from 'rxjs';
import { webSocketListener } from '../../../event-bus';

@Component({
  selector: 'products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.scss'],
})
export class MigrationToolComponent implements OnInit, OnDestroy {
  constructor(private productService: ProductService, private ngZone: NgZone) {}

  ngOnInit(): void {
      webSocketListener.on((message: any) => {
          this.ngZone.run(() => {
              this.checkProductStatus(message);
          });
    });
  }
}