1

Problem:

I work in angular workspace and I import common.module.ts from library (library generated with ng generate library) to my app.module.ts, but when I inject CommonService in app.component.ts I get error:

main.ts:11 ERROR NullInjectorError: R3InjectorError(AppModule)[CommonService -> CommonService -> CommonService]: 
  NullInjectorError: No provider for CommonService!

There is an provider for CommonService in common.module.ts so I expect when I inject service in component no error should occure.

Code:

Library module common.module.ts
import { NgModule } from '@angular/core';
import { CommonComponent } from './common.component';
import { HttpClientModule } from '@angular/common/http';
import { CommonService } from './common.service';

@NgModule({
    declarations: [],
    imports: [],
    exports: [],
    providers: [
        CommonService
    ]
})
export class CommonModule {

}
Application module app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { CommonModule } from 'common';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        HttpClientModule,
        CommonModule
    ],
    providers: [
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}
app.component.ts
import { Component } from '@angular/core';
import { CommonService } from '../../../common/src/lib/common.service';

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

    constructor(private common2: CommonService) {
    }
}

common.service.ts

@Injectable()
export class CommonService {
  constructor() {
    this.initProps();
  }
}
  • With your sample code, I'm able to use CommonService without problems. Can you provide an example on stackblitz ? – Matthieu Riegler Jan 13 '23 at 17:15
  • Is `common.module.ts` located inside library (in your case)? Because this error only reproduced in case I import `common.module.ts` from library (library generated using cli `ng generate library`) – Vladyslav Zhadchenko Jan 16 '23 at 08:34
  • Try to add it in `providers`. I think that injection token is different in both cases. – Antoniossss Jan 16 '23 at 10:25
  • @Antoniossss, injection token is the same (name class). But your solution works. I still have a question: why couldn't service imported from library be injected? Does library have some restrictions that prevents injecting service listed in `providers` array of library module? – Vladyslav Zhadchenko Jan 16 '23 at 11:11
  • Again, I think that injection token is different (it only looks the same) - class you are importing is not the same class instance that is placed in providers of lib module. This is just a though without any technical detail knowledge, but that would explain why there it is not working as `A != A'` but when you use the same class (imported tha same way) then it is simply `A'==A'` – Antoniossss Jan 16 '23 at 11:32
  • @VladyslavZhadchenko i dont think that it is about restrictions but rather a matter of how the code is compiled as library and what actualy `import` does – Antoniossss Jan 16 '23 at 11:33
  • @Antoniossss, if we import `ReactiveFormsModule` (that is part of 3rd party library) we still can inject `FormBuilder` service without no need to provide it in `app.module.ts` `providers` array. So I suppose injection token it's not the root of the problem. – Vladyslav Zhadchenko Jan 16 '23 at 13:18
  • Feel free to search for the explanation (fyi FB is not a service) – Antoniossss Jan 16 '23 at 14:07
  • 1
    @VladyslavZhadchenko i think I know what is wrong. You are not using public-api for your imports. Your import should look like "import X from 'lib-name" just like for RectiveFormsModule you have mentioned;) – Antoniossss Jan 17 '23 at 09:45

1 Answers1

2

You are using different injection token then the one used in the module since your are importing sources directly with

import { CommonService } from '../../../common/src/lib/common.service';

expose it via public-api in your library, then use it via public api just like you do with the module

import { CommonModule } from 'common';

eg

import { CommonService } from 'common';

and then it will work.

Right now you are expecting compiled entity in the library to be equal to entity that is compiled directly into your applicaiton, which will not work (class in the module is not the same class you are importing(compiling it again))

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • After `ng build library` and using `import { CommonModule } from 'common'` it finally works. Thank you! – Vladyslav Zhadchenko Jan 17 '23 at 14:34
  • This saved my day... I had a similar problem while using an `InjectionToken` in my library. I had made a mistake of exporting the file from 2 entrypoints (root and then a /shared public-api). The component in my library was pointing to the file in /shared and the app loading the component was pointing to the root level file (the import was made automatically by the IDE)... This had me scratching my head for a few hours... Your answer pointed me in the right direction, thanks ! – JusuVh Aug 25 '23 at 10:54