No provider for service error in angular2, why do

2019-07-30 12:19发布

问题:

I have a pages.service.ts

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

import { ApiService } from '../../apiService/api.service';

import { Playlists } from '../shared/playlists.model';


@Injectable()
export class PagesService {

  private currentPlaylists: Subject<Playlists> = new BehaviorSubject<Playlists>(new Playlists());

  constructor(private service: ApiService) {

  }


}

This pages service needs another service called ApiService, I inject the way as shown above, it works.

I bootstrap ApiService in main.ts

import { ApiService }  from './apiService/api.service';
import { AppComponent } from './app.component';

bootstrap(AppComponent,[
  disableDeprecatedForms(),
  provideForms(),
  HTTP_PROVIDERS,
  ROUTER_PROVIDERS,
  ApiService
]).catch((err: any) => console.error(err));;

But When I try to inject the PagesService to another component, it gives me error, No Provider for PagesService.

I write that component like this.

    import { Component, ViewChild, ElementRef, Input, Output, EventEmitter } from '@angular/core';
    import { CORE_DIRECTIVES } from '@angular/common';

    import { MODAL_DIRECTVES, BS_VIEW_PROVIDERS } from 'ng2-bootstrap/ng2-bootstrap';


    import { ApiService } from '../../apiService/api.service';
    import { PagesService } from '../../pages/shared/pages.service';


    @Component({
      selector: 'assign-playlist-modal',
      exportAs: 'assignModal',
      providers: [ PagesService ],
      directives: [MODAL_DIRECTVES, CORE_DIRECTIVES, FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES ],
      viewProviders: [BS_VIEW_PROVIDERS],
      styleUrls: ['app/channel/shared/assignPlaylist.css'],
      templateUrl: 'app/channel/modals/assignPlaylistModal.html'
    })

    export class AssignPlaylistModalComponent {


      constructor(private apiService: ApiService, private pageService: PagesService, fb: FormBuilder) {
       }
}

Update: this is my file structure

channel/
--channel.component.ts
--shared/
----assignPlaylist.modal.ts
----addPlaylist.modal.ts
pages/
--shared/
----pages.service.ts
--pages.component.ts

Channel component is the parent of addPlaylist, addPlaylist is the parent of assignPlaylist. This structure will not work

ChannelComponent       
       |
AddPlaylistComponent
       |
AssignPlaylistComponent     ----PagesService----ApiService

I found one solution but don't know why I need to do that,

I add the provider 'PagesService' to ChannelComponent, and also the AssignPlaylistComponent, it will work, no errors.

Even this will work

ChannelComponent            ----PagesService-------------
       |
AddPlaylistComponent
       |
AssignPlaylistComponent     ----ApiService---------------

However, I just want to use PagesService in AssignPlaylistComponent, so I think it not make sense to import PagesService in channelcomponent.ts and make a providers array in it.

回答1:

It is a bit strange, but only components can configure dependency injection in Angular (well, and bootstrap()). I.e., only components can specify providers.

Each component in the component tree will get an associated "injector" if the component has a providers array specified. We can think of this like an injector tree, that is (normally much) sparser than the component tree. When a dependency needs to be resolved (by a component OR a service), this injector tree is consulted. The first injector that can satisfy the dependency does so. The injector tree is walked up, toward the root component/injector.

So, in order for your PagesService to inject a ApiService dependency, that ApiService object first has to be registered with an injector. I.e., in a component's providers array. This registration must occur somewhere at or above the component where you want to use/inject the ApiService .

Your service should then be able to inject the registered ApiService object, because it will find it in the injector tree.

See also Angular 2 - Including a provider in a service.