10

I've got a published library containing a component that uses [routerLink] in it's template. After installing the library in my application, I get the error NullInjectorError: R3InjectorError(AppModule)[Router -> Router -> Router]: NullInjectorError: No provider for Router!

Within the module in the library the RouterModule is imported and looks like this:

@NgModule({
  declarations: [
    Component
  ],
  exports: [
    Component
  ],
  imports: [
    CommonModule,
    RouterModule,
    TranslateModule
  ]
})
export class LibWithComponentModule {
}

Within my application, the RouterModule is configured as follows:

const routes: Routes = [{
  path: '',
  component: RootComponent
}];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

The app.module.ts looks like this:

  declarations: [
    AppComponent,
    RootComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    LibWithComponentModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

But I thought the RouterModule is going to be provided? What am I doing wrong?

Andreas Teich
  • 349
  • 1
  • 2
  • 11
  • can you post the code for the routing file `LibWithComponentModule` if exists? – Kardon63 Sep 29 '20 at 09:29
  • There is no routing file, I just use the [routerLink] directive wihtin the LibWithComponent. – Andreas Teich Sep 29 '20 at 10:05
  • 1
    For a library, if it's meant to be imported into existing apps, as its usually the case, you should not import browser module, use common module instead. Also Routermodule should be imported by using forchild. Forroot is for root module only. – meblum Sep 29 '20 at 12:28
  • In this case I just need the template directives provided by the router module, not more or less, so I do not use forChild at all. Could that be the problem? – Andreas Teich Sep 29 '20 at 12:30
  • Nope, using forChild seems not to be the problem solver. Now build of the lib fails with the message: Function calls are not supported in decorators but 'RouterModule' was called. – Andreas Teich Sep 29 '20 at 12:35
  • Did you got the answer? I'm also facing the same issue. – Mayank Kataria Nov 22 '20 at 13:45
  • Facing the same issue – Jusmpty Nov 27 '20 at 08:59

5 Answers5

13

I was facing this exact same scenario you described in a large application I'm working on. My main application imports a published npm component package that contains a component that leverages the routerLink directive. When running the application, I run into the same R3InjectorError you mention, even though RouterModule is definitely correctly imported in all modules that need it.

The root cause of the problem in my case, was the fact that this npm package explicitly listed @angular/router as one of the dependencies instead of a peerDependency (which in the case of a library it should have been). This means @angular/router will be installed both in your node_modules, as well as in node_modules/LIBRARY/node_modules!

What happens is that at runtime, the RouterModule your published component uses has a different InjectionToken than the RouterModule your application provided using a RouterModule.forRoot(). The published component's RouterModule refers to node_modules/LIBRARY_NAME/node_modules/@angular/router, whereas the main application has provided the one in node_modules/@angular/router.

So in conclusion: the fix is to not explicitly have any @angular packages listed in your library as a dependency, but correctly mark them as a peerDependency. Here's an interesting read on managing dependencies from the ng-packagr documentation.

For reference: I'm not sure if this exclusively Ivy related, but in my scenario I was running Angular 11 with Ivy enabled.

The error message is definitely very confusing in this case, as the injected service is named Router twice, even though they're referencing different instances.

Hope this solves your problem too, I spent quite some time to figure this out!

Nils Tijtgat
  • 206
  • 4
  • 9
  • We are using Bit, where we can preview our Angular packages. The parent module that "previews" (a "composition" of) the package, needs the "RouterModule" imported and instantiated with "RouterModule.forRoot([])" – John Spiteri Jan 22 '22 at 11:40
4

I got the same error with a service that used @angular/router. I was able to fix it by replacing

@Injectable()

with

@Injectable({
  providedIn: 'root'
})

inside the service class.

Pascal R.
  • 2,024
  • 1
  • 21
  • 35
1

For me, the problem was a bit like @NilsTitjgat explained, but I had to keep the library as dependency.

If like me you have to do it, then the problem is coming from your application importing another version of the library that the one imported into this library.

Meaning if

MainApp

"dependencies": { 
  "@my/lib": "1.0.0",
  "@another/lib": "1.0.0" 
}

@my/lib

"dependencies": { 
  "@another/lib": "1.2.0"  // <-- The version is higher
}

Then you will face the same error. The way to fix this would be to bump the @another/lib version into MainApp from 1.0.0 to 1.1.0.

Yes, you shouldn't import it like this. If you can, put it under peerDependencies as @NilsTitjgat mentioned

Raphaël Balet
  • 6,334
  • 6
  • 41
  • 78
0

Import HttpClient into your .service.ts

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

Import HttpClientModule into app.module.ts and add HttpClientModule to imports array

import { HttpClientModule } from '@angular/common/http';

 imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
Bhanu Pratap
  • 1,635
  • 17
  • 17
0

I faced a similar error very recently and the root cause is not related to peerDependency so I am sharing it here.

The error reported was

NullInjectorError: R3InjectorError(AppModule)[NgControl -> NgControl -> NgControl -> NgControl]: NullInjectorError: No provider for NgControl!

The root cause of the error was below:

My angular app is using a custom component(imported from an internal library). The custom component's view had a checkbox element with a formControlName binding. A custom directive was also added on this checkbox to control the enable/disable behavior. This directive had a dependency of NgControl (specified in constructor like constructor(private ngControl: NgControl) ).

While making some changes, I removed the formControlName binding on the checkbox in custom component but did't removed the custom directive applied on it. This lead to NullInjectorError: R3InjectorError error which got resolved when I removed the custom directive along with the formControlName binding removal.

Kaashan
  • 352
  • 3
  • 12