Home > Mobile >  Angular parent and children communication using a service?
Angular parent and children communication using a service?

Time:02-14

I've started learning Angular, and I run into this example from official docs regarding parent-service communication using a service:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class MissionService {

  // Observable string sources
  private missionAnnouncedSource = new Subject<string>();
  private missionConfirmedSource = new Subject<string>();

  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();

  // Service message commands
  announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);
  }

  confirmMission(astronaut: string) {
    this.missionConfirmedSource.next(astronaut);
  }
}

I'm a bit confused by this part:

  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();

I understand that .asObservable() creates a new Observable with this Subject as the source. However, why do we need it ? missionAnnouncedSource is already an observable. Why don't we just simply have a service like this:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class MissionService {

  // Observable string sources
   missionAnnouncedSource = new Subject<string>();
   missionConfirmedSource = new Subject<string>();

  // Service message commands
  announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);
  }

  confirmMission(astronaut: string) {
    this.missionConfirmedSource.next(astronaut);
  }
}

Of course, I would need to adjust code in components to make it work, but I do not see any issues with that:

  //astronaut.component.ts

  constructor(private missionService: MissionService) {
    this.subscription = missionService.missionAnnouncedSource.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    });
  }

Is this some sort of convention or I am missing something?

CodePudding user response:

You don’t need it, but the idea is that if you only expose an observable, it is not possible to next the public variable - it should only be done from within the service.

CodePudding user response:

Your question give me the same doubt. So I look in to it. This is what I have found:

From de RxJS docs

A Subject is like an Observable, but can multicast to many Observers. Subjects are like EventEmitters: they maintain a registry of many listeners.

So you can do the same just that Observable cant modify the value with a next(value) call.

This article is quite good, explains your doubt about best practice and this example is from there:

In the RxJS world it's considered best practice to only expose Subjects to the parts of your application that would add new data into the Observable sequence. This is the same idea behind only allowing write access to certain parts of your application, private and public class members, etc.

To create an Observable from a Subject, you can simply invoke asObservable on any Subject:

let currentUserSubject$ = new BehaviorSubject() < string > 'Eric';
let currentUser$ = currentUserSubject$.asObservable();

We now have a new variable called currentUser$ that is an Observable of currentUserSubject$'s observable sequence. To see how this works, lets subscribe to the currentUser observable and then add some data to the currentUserSubject$:

let currentUserSubject$ = new BehaviorSubject() < string > 'Eric';
let currentUser$ = currentUserSubject$.asObservable();

currentUserSubject$.subscribe(val => {
  console.log(val);
});
// => 'Eric'

currentUserSubject$.next('hello');
// => 'hello'

Note that if you try and call currentUser$.next(), it will throw an error because Observables can only observe a sequence - thus providing you with read-only access to the currentUserSubject!

  • Related