0
votes
  • I have a component A from where I am broadcasting data to Component B using behaviourSubject for my usecase where on every click on a button in component one http request should trigger in component B.
  • In component B i am Subscribing to the brodcasted observable from Component A.

Component A :

import { Component, OnInit } from '@angular/core';
import { MessagingService } from '../messaging.service';

@Component({
  selector: 'app-comp-a',
  templateUrl: './comp-a.component.html',
  styleUrls: ['./comp-a.component.css']
})
export class CompAComponent implements OnInit {

  public i= 0;

  constructor(public message: MessagingService) { }

  ngOnInit() {

  }

  broadcast(){
    this.message.broadcast({data:`Broadcasted_${this.i}`});
    this.i++
  }

}

Component B:

import { Component, OnInit } from '@angular/core';
import { MessagingService } from '../messaging.service';
import { switchMap } from 'rxjs/operators';
import { of } from 'rxjs';

@Component({
  selector: 'app-comp-b',
  templateUrl: './comp-b.component.html',
  styleUrls: ['./comp-b.component.css']
})
export class CompBComponent implements OnInit {
  public data;
  constructor(public message: MessagingService) {}

  ngOnInit() {
    this.message.getData().pipe(
      switchMap(res => {
        /**
         * here some service call based on brodcasted data.
         * 
         * Lets say service returns json in format 
         * {
         *    data:[{},{}]
         * }
         */
        return of([res.data]);
      })
    ).subscribe(res => {
      /**
               * So in actual use case I will get 
               *  {
               *   data:[{},{}]
               *  }
               * in subscription.
               *
               *  now lets assume sometime I get data as null and i tried to access it as res.data[0].some_property
     then it will throw js error Cannot read property '0' of undefined so subscription breaks and doesnt complete and stops. and then after subsequent broadcast from comp A doesnt triggers subscription in comp B.. is it expected behaviour?
               */

      // let a = this.data[0] //this is delibrate error to simulate my realtime issue
      this.data = res
    }, (error) => {
      console.log("Error happened" + error)
    }, () => {
      console.log("the subscription is completed")
    })
  }

}

Service :

import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject } from 'rxjs';
@Injectable()
export class MessagingService {

  /**
   * Subject to notify the offer console
   */

  private _change_in_year_month = new BehaviorSubject<any>({ data:'old data' });
  public change_in_year_month = this._change_in_year_month.asObservable();

  constructor() { }

  /**
   *
   * @param data  data contains either year or (year and month)
   * This method will broadcast data to offer console to execute service call
   */
  broadcast(data) {
    this._change_in_year_month.next(data);
  }

  /**
   * Method will return observable of Subject which can be subscribed in
   * offer console component to execute service call
   */
  getData() {
    return this.change_in_year_month;
  }

}

Now lets say somehow js error occurred (may be Cannot read property '0' of undefined )in the subscription in Component B then my further javascript execution stops and doesn't listen subsequent brodcasted values.

Is this expected behaviour of Rxjs. How shall I handle js error occurring in subscribe block .

Problem can be simulted at Stackblitz. Initially click on broadcast button then you can see data being displayed. Now uncomment line 38 to simulate the issue and click on broadcast. It will never listen to subsequent calls.

1
have a look at this - Umair M
Since the error happens in you code that is fully under your control you can wrap it with try {...} catch () {...} and just ignore the error. - martin
@martin so its expected behavior right ? Subsequent calls will not get subscribed after error right ? ... I can do try catch for sure... - user1608841

1 Answers

1
votes

If observable dies it calls it error handler and they are closed you can't send anything through them that means they are closed everything upstream from that including the interval is dead.

what if we want to live.

sheilding the main observer chain is the solution
put catch inside of switchmap whenever a request is fired switchmap creates the ajax observable and this time with the catch.
switchMap() does not care if inner Observable has completed it will only complete when outer Observable has completed. Even though inner Observable chain dies,outer Observable chain stays alive because error handler has not been called for outer Observable chain.
example

switchMap((value)=>this.http.get('url' + value).pipe(catchError(() => {return empty()}))
            ))

How to keep an Observable alive after Error in Angular?