How exactly works the services hierarchy in this Angular 2 application?
Asked Answered
H

1

3

I am very new in Angular 2 and I have the following question about services.

Into the main view (the one related to the app.component.ts class) I have this situation:

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-md-8 col-md-offset-2">
      <app-new-account (accountAdded)="onAccountAdded($event)"></app-new-account>
      <hr>
      <app-account
        *ngFor="let acc of accounts; let i = index"
        [account]="acc"
        [id]="i"
        (statusChanged)="onStatusChanged($event)"></app-account>
    </div>
  </div>
</div>

So into this view I have 2 sub component (app-new-account and app-account).

Into the main AppComponent component class I have:

import {Component, OnInit} from '@angular/core';
import {AccountsService} from './accounts.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [AccountsService]
})
export class AppComponent implements OnInit {

  accounts: {name: string, status: string}[] = [];

  // Injectiong the AccountsService:
  constructor(private accountsService: AccountsService) {}

  ngOnInit() {
    this.accounts = this.accountsService.accounts;
  }

}

Where I am defining the AccountsService as a service by this line into the component decorator:

providers: [AccountsService]

From what I have understood it specify that this class is AccountsService have to be registered as service of the AppComponent main component and for all its subcomponent. Is it this assertion true or am I missing something?

So, it means that the two sub components classes related to the previous app-new-account and app-account tags share the same instance of the AccountsService class as service?

Is this the reason because in the providers array of these 2 sub somponents I have not the AccountsService?

Is it my reasoninc correct or am I missing something?

Hosmer answered 7/8, 2017 at 14:18 Comment(0)
L
8

So, it means that the two sub components classes related to the previous app-new-account and app-account tags share the same instance of the AccountsService class as service?

Yes. An injector is created per component instance. Since injector is hierarchical all children of the component access the same instance of the service as the parent. Unless they define a service in its own providers array using the same token. Here is the diagram of injectors:

// all components share the same instance
     AppComponentInjector
  providers: [AccountsService]
       /               \
      /                 \
 app-new-account     app-account

    // app-new-account has its own instance
             AppComponentInjector
          providers: [AccountsService]
           /                     \
          /                       \
   app-new-account                 app-account
   providers: [AccountsService]

     // every component has its own instance
         AppComponentInjector
      providers: [AccountsService]
       /                           \
      /                             \
  app-new-account                   app-account
  providers: [AccountsService]      providers: [AccountsService]

Host elements

I would also provide a bit more details here as I think this is not clearly explained elsewhere. The injector is created on a component/directive host element. It means that a directive creates its own injector on the host element it's placed on.

So if you put a directive with providers on the hr element in the AppComponent template:

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-md-8 col-md-offset-2">
      <app-new-account (accountAdded)="onAccountAdded($event)"></app-new-account>
      <hr somedirectivewithproviders>  <----------------

You would have the following hierarchy:

  // all components and directives share the same instance
                AppComponentInjector
            providers: [AccountsService]
        /               |                  \
       /                |                   \
app-new-account somedirectivewithproviders   app-account

It means that if somedirectivewithproviders defines AccountsService and injects it, it will get the new instance just as components. But the components will still get the instance from the AppComponentInjector:

  // all components and directives share the same instance
                    AppComponentInjector
                 providers: [AccountsService]
        /                      |                    \
       /                       |                     \
// gets same instance   //gets new own instance      // gets same instance   
 app-new-account      somedirectivewithproviders     app-account
                      providers: [AccountsService]
Levey answered 7/8, 2017 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.