1
votes

I've got a module composed with a Component and a bunch of sub component. There is also a service dedicated to this module.

I am not sure to understand the injection mecanism for my needs. What's i want to do is to inject the Service into all sub component.

When i inject Service with a provider into components it's ok but i wanted to set provider on module level.

Module

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

import { ChangeUserComponent } from './change-user.component';
import { ChangeUserSidebarComponent } from './sidebar/sidebar.component';
import { ChangeUserUserListComponent } from './user-list/user-list.component';

import { ChangeUserService } from './change-user.service';

@NgModule({
    declarations: [
        ChangeUserComponent,
        ChangeUserUserListComponent,
        ChangeUserSidebarComponent
    ], 
    providers      : [
        ChangeUserService // <-- when i set that it's not working
    ],
    exports     : [
        ChangeUserComponent
    ]
})

export class ChangeUserModule
{
}

Sub component

import { Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeUserService } from '../change-user.service';

@Component({
    selector   : 'change-user-sidebar',
    templateUrl: './sidebar.component.html',
    styleUrls  : ['./sidebar.component.scss'],
    //providers:  [ ChangeUserService ] // <-- with that the service is correctly injected
})
export class ChangeUserSidebarComponent
{

  public activeNode: any;

    constructor(
      private _changeUserService: ChangeUserService
    )
    {
    }
}

Service

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ChangeUserService 
{
    constructor(
        private _http: HttpClient
    ){}
}

Service is correctly injected when i set Provider on the component level but i wanted to set it on module level.

Edit : When i set keyword provider on Component level : everything is ok

When is set keyword providers on module level :

Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[ChangeUserSidebarComponent -> ChangeUserService]: StaticInjectorError(Platform: core)[ChangeUserSidebarComponent -> ChangeUserService]: NullInjectorError: No provider for ChangeUserService!

Is there a way to do that ? Am I missing something ?

2
Is there a problem? Your module snippet is correct, that is how you register a singleton provider over the whole app. You'll have to show us a specific error if you're getting one.UncleDave
The injection is done in the constructor, not in the providers section. It should work as you want. What's the error ?Mehdi Benmoha
Yes, when i set provider on Module Level, compiler yell, i have edited the question .I don't want to register it for the whole app (injectable provided in root ?) but just for the module and all Component imported by this module (in the example ChangeUserComponent, ChangeUserUserListComponent & ChangeUserSidebarComponent). The goals is to register service only on module level for all the imported component ant not to set keyword providers into each @Component block of imported components.T. Grandemange
You can't scope a provider to a module unless it is a lazily loaded module. Anything can inject a provider if it has access to the type.UncleDave
Again, there's nothing wrong with your code and it shouldn't produce that error, can you create a minimal recreation of the problem on stackblitz?UncleDave

2 Answers

0
votes

I wouldn't lock anyone in a dungeon to do that ;-) !

Finally i've decided to follow the first solution and put the service Injectable for Root. Don't want to do complex things to avoid something that would/should never happened (i-e : use the service into another component than the one devoted to this service).

Initially what i really wanted to do was to scope the service to it's module only, and provide it to the children components of the module.

Put the service for Root allow me to share the service and i will be assuming that the service should not be used by other parts of the app.

Anyway i still not know why set providers fir the service into the module isn't working in my context.

0
votes

Well, this is interesting.

On the component level you can have a service injected (so you can inject the service directly in each sub component, but that would not only be troublesome, but also every component will have its new instance of the service)

But if you lock me down a dungeon and say to do it by any means here is what I will do. I would lazy load that module.

Explanation:

  1. We have two modules (AppModule and LazyModule) that provide the same service.
  2. As our second module is lazy , Angular doesn’t know about its existence. .This means that any service listed in the providers array of our LazyModule isn’t available because the root injector doesn’t know about LazyModule ... yet. When we activate the route, lazy module will be loaded and new injector created. Imagine a tree of injectors, on top there is the root injector and for each lazy module, new child injector will be created.
  3. All services from root injector will be added to child injector. If root injector and child injector provide the same service, Angular prefers service instances from child injector. So every lazy component gets the local instance of the service, not the instance in the root application injector.
  4. So the Lazy will work with its own another reference, and the rest of the app will have it