Trying to make Angular dependency injection work

343 Views Asked by At

My Angular dependencies aren't working and I don't know why. All the resources I've seen indicate that this should work:

import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>'
})
export class AppComponent {
  constructor (private route: ActivatedRoute) {} // I'm the problem it's me
}

That line with the constructor always gives me this browser error: Error: NG0202: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid. It's not specific to ActivatedRoute; I've tried this syntax with other dependencies and it happened with all of them.

My thought is that, if the Angular code is right, the problem lies in how my code is being loaded. I'm using jsbundling-rails and esbuild. This is my tsconfig.json:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "baseUrl": "./"
  }
}

It'd be great if someone knew how to fix this, but I'm also trying something else to get around it. I saw another question where someone was getting similar errors while using Webpack. He said he got it to work by "using the @Inject decorator in the component constructor." I couldn't make it compile using the syntax he had:

import { Inject } from '@angular/core';
...
export class AppComponent {
  constructor(@Inject(ActivatedRoute) private route: ActivatedRoute) {}
  // Decorators are not valid here. ts(1206)

This, on the other hand, does compile:

export class AppComponent {
  private route = Inject(ActivatedRoute);

But then the value of this.route isn't an ActivatedRoute object, it's this stock function from the Angular decorators code: function ParamDecorator(cls, unusedKey, index) { ... }. I tried other ways of phrasing it and got these errors:

export class AppComponent {
  private route = @Inject(ActivatedRoute);
  // Expression expected. ts(1109)
@Injectable({ providedIn: 'root' })
export class AppComponent {
  private route = inject(ActivatedRoute);
  // Cannot find name 'inject'. Did you mean 'Inject'? ts(2552)

That last one is right from the Angular docs but clearly I'm doing something bizarrely wrong. What am I supposed to do with these? All I want is usable dependencies ;_;

2

There are 2 best solutions below

0
On BEST ANSWER

Alright this is weird but remember how I said this didn't work:

constructor(@Inject(ActivatedRoute) private route: ActivatedRoute) {}

Well it does work, VSCode just says it doesn't. I'm not sure how to tell VSCode it's wrong, but I guess that's a better problem to have.

3
On

The error message

dependency at index 0 of the parameter list is invalid

reveals that angular has understood that this parameter is a "dependency" it should inject, but that this particular dependency is "invalid" somehow.

If you search the error code NG0201 in the angular docs, you'll find NG0201: No provider for {token} found.

That is, this error message is angular telling you "I can't find an ActivatedRoute? Where am I supposed to get this from?". The most likely cause is that you have forgotten to import the RouterModule.

BTW, injecting an ActivatedRoute into AppComponent doesn't make sense. Its docs say:

ActivatedRoute

Provides access to information about a route associated with a component that is loaded in an outlet.

Since the AppComponent is not loaded in an outlet, and the route will change while the AppComponent lives, the ActivatedRoute, even if it were injected, would be the route the was active when the AppComponent first loaded, not the route that is active now.