Search code examples
arraysangularfilteringbroadcast

Filter a broadcasted property in Angular 9


I have a dbService that calls the database!

//DB service code -----------------------

 private changedEvents = new BehaviorSubject<IEvent[]>(null);
  broadCastEvents = this.changedEvents.asObservable();

  getEvents() {
    this.http.get<IEvent[]>(this.configUrl + 'Event/GetEvents').subscribe(
      (data: IEvent[]) => {
        this.changedEvents.next(data)
      });
  }

In my component on ngOnInit I starts listening to this

  ngOnInit(): void {
    this.dbService.broadCastEvents.subscribe(data => {
      this.events = data;
    })
   // this.dbService.getEvents();
  }

Now all of this working like a charm! But now I'm only interested in records where this.events.type == 2

I tried by a standard filtering like below!

  ngOnInit(): void {
    this.dbService.broadCastEvents.subscribe(data => {
      this.events = data.filter(event => event.eventTypeRefId == 2);
    })
   // this.dbService.getEvents();
  }

But it results in the following Error!? Any ideas how to this in a better way (that works :-))

core.js:6241 ERROR TypeError: Cannot read property 'filter' of null
    at SafeSubscriber._next (start-training.component.ts:26)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
    at SafeSubscriber.next (Subscriber.js:122)
    at Subscriber._next (Subscriber.js:72)
    at Subscriber.next (Subscriber.js:49)
    at BehaviorSubject._subscribe (BehaviorSubject.js:14)
    at BehaviorSubject._trySubscribe (Observable.js:42)
    at BehaviorSubject._trySubscribe (Subject.js:81)
    at BehaviorSubject.subscribe (Observable.js:28)
    at Observable._subscribe (Observable.js:76)

Solution

  • There are multiple ways for it. One way is to use array filter like you did. Other way would be to use RxJS filter pipe as shown by @enno.void. However both these methods might still throw an error when the notification is null. And since the default value of your BehaviorSubject is null, there is high probability of hitting the error again.

    One workaround for it is to use ReplaySubject with buffer 1 instead. It's similar to BehaviorSubject in that it holds/buffer the last emitted value and emits it immediately upon subscription, except without the need for a default value. So the need for initial null value is mitigated.

    Try the following

    private changedEvents = new ReplaySubject<IEvent[]>(1);
    broadCastEvents = this.changedEvents.asObservable();
    ...
    

    Now the error might still occur if you were to push null or undefined to the observable. So in the filter condition you could check for the truthiness of the value as well.

    ngOnInit(): void {
      this.dbService.broadCastEvents.subscribe(data => {
        this.events = data.filter(event => {
          if (event) {
            return event.eventTypeRefId == 2;
          }
          return false;
        });
      });
    }