Sergey Pahuta
Sergey Pahuta

Reputation: 195

Angular 6 providedin doesn't work -> StaticInjectorError

I'm trying to use 'providedin' feature in Angular but receive the error "StaticInjectorError(AppModule)[DashboardComponent -> DashboardService]:"

@Injectable({
  providedIn: DashboardModule
})
export class DashboardService {
  getContent() {
    return 'Dashboard Service works!!!';
  }
}

Full demo https://stackblitz.com/edit/angular-kbkjet Thanks for you effort!

Upvotes: 12

Views: 7140

Answers (5)

Michael
Michael

Reputation: 854

The problem turned out to be VSCode automatically adding the service as a provider using intellisense to add the service to the constructor.

@Component({
  selector: 'my-selector',
  standalone: true,
  imports: [ CommonModule ]
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  providers: [MyRootService], // <-- This creates new instances, remove for static instance
})

Upvotes: 0

user5807091
user5807091

Reputation:

Make sure you have your module imported in the test like this:

beforeEach(() => TestBed.configureTestingModule({
  imports: [DashboardModule]
}));

Upvotes: 1

DeborahK
DeborahK

Reputation: 60518

  • 98% of the time, use providedIn = 'root'. It will register the service with the root application injector, will be tree shaken, and will be available to any component that needs it. The tree shaking will ensure the service is only included in the bundles where it is used.
  • Use the providers array in a component if the service only needs to be provided in the component and its nested children. (For service isolation at the component level or if you need multiple instances of the service per component.)
  • Don't use the providers array in a module (this is old syntax and it no longer recommended)
  • Use providedIn='lazymodule' if you want to limit access to a service to a particular lazy loaded module. It will then require an additional module to prevent the circular dependency issue. This provides service isolation at the module level. If any other component in the application outside of this lazy loaded module attempts to reference the service an "out of injector scope" error is generated.

See this for more information on the "additional module": https://www.youtube.com/watch?v=jigR_jBhDMs&feature=youtu.be

Sample code here: https://github.com/web-dave/provide-in-test

Discussion of the circular dependency issue here: https://github.com/web-dave/provide-in-test/issues/1

Upvotes: 11

David
David

Reputation: 34435

The stackblitz example posted by Stepan Suvorov does not work when using

providedIn: AppModule

because of a dependency issue, which causes AppModule to be unresolved (undefined).

If you add a console.log(AppModule) just above the @Injectable decorator, the output is undefined.

Note You cannot actually see that dependency issue on stackblitz, but you can if you replicate the project on a local angular cli, you'll see the following warnings.

WARNING in Circular dependency detected: src\app\app.component.ts -> src\app\my.service.ts -> src\app\app.module.ts -> src\app\app.component.ts

WARNING in Circular dependency detected: src\app\app.module.ts -> src\app\app.component.ts -> src\app\my.service.ts -> src\app\app.module.ts

WARNING in Circular dependency detected: src\app\my.service.ts -> src\app\app.module.ts -> src\app\app.component.ts -> src\app\my.service.ts

I don't think there is any point in using using AppModule in providedIn, you may as well use root. But if you want your service to only be provided in a child module, this should work like in this stackblitz demo

Here is a related github issue

Note: when declaring an injectable service, if you use providedIn with a module value, the specified module cannot be a module which declares a component which uses that service (quite a mouthful)

Upvotes: 2

Sergey Pahuta
Sergey Pahuta

Reputation: 195

Finally I have found the solution: https://angular.io/guide/providers#providedin-and-ngmodules Service also should be mentioned in the providers section of module.

@NgModule({
  imports: [CommonModule],
  declarations: [DashboardComponent],
  exports: [DashboardComponent],
  providers: [DashboardService]
})

Demo has been corrected. Thank you guys!

Upvotes: -3

Related Questions