Alex Lockwood
Alex Lockwood

Reputation: 83311

Sharing an Angular 2 service between child components who don't share the same parent component

Let's say I have an Angular 2 that is structured as follows:

enter image description here

In other words, there is a root parent component A that contains instances of two distinct children components B and C.

Now say I want to create a MyService class to be shared across each vertical column of children components. More specifically, I want to be able to inject MyService into component B and component C's constructors, with Angular creating two instances of the service overall (one for the first column of child components and another for the second column of child components).

One way to do this is to wrap each column of child components in a intermediate component P and then declare MyService as a provider in its @Component decorator using providers: [MyService]. This ensures that each instance of P (and therefore all of its children components as well) will receive their own instance of MyService:

enter image description here

However, I would like to avoid this solution because creating an intermediary wrapper component like this seems like a lot of extra boiler plate and it also requires restructuring how components are laid out in component A's template.

Is there an easy way to achieve this in Angular 2? Thanks!

Upvotes: 3

Views: 1819

Answers (2)

Err0r500
Err0r500

Reputation: 25

And what about a static EventEmitter both components subscribe to ?

I saw that somewhere, one day (if I remember I'll put a link). I use it right now without visible drawback, I'll see when the app grows.

//the "commands dispatcher" class :

import { EventEmitter } from '@angular/core';

export class CommandsDispatcherService {
  private static store: { [channel: string]: EventEmitter<any> } = {};

  static get(channel: string): EventEmitter<any> {
    if (!this.store[channel]) {
      this.store[channel] = new EventEmitter();
    }
    return this.store[channel];
  }
}

Components A & B (without any hierarchical relationship) just import the class (no provider), subscribe to it on init and use the get method to communicate with each other on their own private channel. I found that pretty cool.

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 223194

Parent component that hosts the injector and MyService provider is the correct solution. This is how Angular 2 DI works. Even if there were a singleton service, MyServiceFactory that can create MyService class instances, how would it determine that B and C should receive a common MyService instance, considering that there are several Bs and Cs?

Parent component is preferable, unless there are unresolvable layout issues. Otherwise it can be a directive with MyService provider,

@Directive({
  selector: '[p]',
  providers: [MyService]
})
class P {}

that results in transparent layout with

<ng-container p>
  <b></b>
  <c></c>
</ng-container>
<ng-container p>
  <b></b>
  <c></c>
</ng-container>

Upvotes: 2

Related Questions