2

I am trying to share service data between parent/child components in angular 4. I have a working code but I am not clear if thats the best option. I am using an injectable service class to communicate between parent --> child by creating Subjects and subscribing to observable methods. Now to communicate backwards i:e child --> parent, I am re-using the same service class by creating Subjects and subscribing to observable in parent. That way I am subscribing to observables in both child and parent, is it the right approach? I have seen elsewhere that people have suggested @Output decorator to communicate between child --> parent, but my code is working with the subscribe mechanism. Will it cause any issues in future like memory leakage?

Parent Component

  constructor(private _textdataservice: TinyEditorService, private _gmapService: GmapService) {
this.subscription = this._gmapService.getMessageC2P().subscribe((message) => {
  this.message = message;
  this.childCallingParent(message);
});
this.subscription = this._gmapService.getStoreSearchRequest().subscribe((radius) => {
  this.radius = radius;
  this.retrieveNearByLocations(radius);
});

}

Child Component -->

  constructor(private _gmapService: GmapService) {
// subscribe to home component messages
this.mainSubscription = this._gmapService.getMessageP2C().subscribe((addresses) => {
  this.mainCoordinates = addresses;
});

this.storeSubscription = this._gmapService.getMessageP2CStore().subscribe((addresses) => {
  this.storeCoordinates = addresses;
  if(this.storeCoordinates){
    for(let coord of this.storeCoordinates){
      this.addNearbyStoremarker(coord.name, coord.latitude, coord.longitude);
    }
  }
});

}

Service -->

export class GmapService {
  private _dataurl='/assets/gmapmarkers.json';
  constructor(private _http: Http){}

  private parentSubject = new Subject<IGmapData[]>();
  private storeSubject = new Subject<IGmapData[]>();
  private childSubject = new Subject<String>();
  private radiusSubject = new Subject<number>();

  sendMessageP2C(latLngArray: IGmapData[]) {
    this.parentSubject.next(latLngArray);
  }

  sendMessageP2CStore(latLngArray: IGmapData[]) {
    this.storeSubject.next(latLngArray);
  }

  sendMessageC2P(message: string) {
    this.childSubject.next(message);
  }

  requestNearByLocations(radius: number) {
    this.radiusSubject.next(radius);
  }

  clearMessage() {
    this.parentSubject.next();
    this.childSubject.next();
  }

  getMessageP2C(): Observable<IGmapData[]> {
    return this.parentSubject.asObservable();
  }

  getMessageP2CStore(): Observable<IGmapData[]> {
    return this.storeSubject.asObservable();
  }

  getMessageC2P(): Observable<string> {
    return this.childSubject.asObservable();
  }

  getStoreSearchRequest(): Observable<number> {
    return this.radiusSubject.asObservable();
  }

  getStoreMarkers(): Observable<IGmapData[]> {
      return this._http.get(this._dataurl)
        .map((response: Response) => <IGmapData[]> response.json());
  }
}
whizKid
  • 83
  • 2
  • 8

3 Answers3

3

I would say that it is better to use @Input() and @Output() if you need to communicate back and forth between your Parent and Child. The reason being that Angular will destroy/create subscriptions for you as your components come to life or disappear. Where Subjects come in handy is when you need to broadcast an event across components that have no parent/child relationship. An example of Subject use is facebook. When a message is received, multiple parts of the page will react to that event without being related to each other.

However, if you implement ngOnDestroy to unsubscribe from your subjects, that should keep your solution tidy. The risk of using the Subject approach is to end up having hundreds of subjects created in your App which can lead to performance issues.

Mehdi
  • 2,263
  • 1
  • 18
  • 26
1

You can cancel subscriptions in the ngOnDestroy lifecycle hook to prevent memory leaks as described in this answer: [how to unsubscribe several subscriber in angular 2

But unless you need this extra complexity just using the @Output and EventEmitter is probably a good idea.

Brendan Whiting
  • 494
  • 3
  • 13
  • Thanks for the reply.. I am already using ngOnDestroy in both parent and child. Also agree with the fact that 2 way pub-sub between parent-child is not a good idea since I didn't find a single implementation online. I could use @output decorator, but wanted to keep the code in one place in the service class. Should I use output decorator in child? – whizKid Nov 29 '17 at 00:43
  • The @Output property would be in the child component, but that's only if you're passing data directly between child and parent and not through some external service. – Brendan Whiting Nov 29 '17 at 01:13
1

@Input @Output can be slow and becomes complicated when you pass from child of a child.

Store approach is better and flexible, if you ever want to use that data in other components too.

Vinny
  • 149
  • 1
  • 4