angular: New `provideIn: AppModule` syntax not working

I’m submitting a…

[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

When using the new provideIn syntax for injectable services as documented on https://angular.io/guide/dependency-injection#injectable-providers:

@Injectable({
  providedIn: AppModule,
})
export class HeroService {
} 

And request the service in a component:

@Component({})
export class AppComponent {
  title = 'app';
  constructor(s: HeroService) { }
}

I get this error:

ERROR Error: StaticInjectorError(AppModule)[AppComponent -> HeroService]: 
  StaticInjectorError(Platform: core)[AppComponent -> HeroService]: 
    NullInjectorError: No provider for HeroService!

Expected behavior

I would expect the service to be injected as singleton for the entire AppModule

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/angular-ggecbg

What is the motivation / use case for changing the behavior?

I’m trying to figure out how to provide a service as a singleton in a single module using the new provideIn syntax. It is documented here: https://angular.io/guide/dependency-injection#injectable-providers but does not seem to work. Or I’m I making a mistake?

Environment


Angular version: X.Y.Z


Browser:
- [x] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: 10.1.0 
- Platform:  windows
- Angular CLI: 6.0.3
- Angular: 6.0.2

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 48 (30 by maintainers)

Commits related to this issue

Most upvoted comments

@nicojs ES modules support circular dependency ONLY when it’s not used eagerly, but all metadata were used eagerly.

A simple console.log could help you confirm what the problem is: https://stackblitz.com/edit/angular-xghrcp?file=src/app/hero.service.ts. It’s indeed an undefined value and being skipped by Angular.

So it’s not a problem of Angular, from Angular’s perspective, you just wrote:

@Injectable({
  providedIn: undefined
})
export class SomeService {}

Angular CLI already provides --show-circular-dependencies functionality, every time a circular dependencies occurs, you need to fix it first, rather than just believing it won’t break anything.

@gkalpak The value of providedIn has nothing to do with loading/bundling, only determines whether it is ALLOWED to use after being loaded.

And providedIn: 'root' means allowed anywhere.

Consequences for performance/tree-shakability aside, I feel like I’m just following the documentation on the angular.io main site, right? Also, the TypeScript API for using a Type is there, enforcing my believe that it should work.

@nicojs I’ve seen these things come and expressed my concerns here when Angular v6 wasn’t even released. But I think we should assume the Angular authors have had their reasons for why they designed the API this way.

In fact the docs say:

Creating tree-shakable providers […] In the example above, providedIn allows you to declare the injector which injects this service. Unless there is a special case, the value should always be root.

What the docs or migration guide should make clear, though, is that a module-[provides]->service relationship shouldn’t be systematically migrated to the inverse service-[providedIn]->module relationship but onto service-[providedIn]->"root" (see the linked issue thread).

@chengengliu, does this help you? https://angular.io/guide/providers#providedin-and-ngmodules

Could you describe what’s happening?

EDIT: Maybe this repo will help you. It’s a ModuleInjector demo I made. The readme explains what’s happening. Basically, if you’re trying to use another module with providedIn, look at how this example uses the AnimalService and the LazyModule. https://github.com/kapunahelewong/module-injector-tree

@kapunahelewong Thanks, it’s really helpful!

@kumaran-is … did you read https://github.com/angular/angular/issues/25784 ? The key point of the theme are cases as:

https://github.com/angular/angular/issues/25784#issuecomment-417919896 https://github.com/angular/angular/issues/25784#issuecomment-418514688

… so you need always additional module. Otherwise, you have featureModule as undefined.

@jbogarthyde thanks for your work.

I think the warning already helps people. What I’m still missing why you would want to use provideIn: MyModule. Is there any use case for that?

@trotyl If we provide all service in 'root' instead of the LazyLoadedModule, won’t it increase the initial bundle size?? Or since these are tree shakable will it be bundled only with the module that actually uses it??

From Angular side, it shouldn’t use options.providedIn !== undefined but 'providedIn' in options (need to make it closure-safe) to detect possible circular-dep issue, that way it could produce a better error message.

Ref: https://github.com/angular/angular/blob/13cb75da8b02ed7aa60508dbb5ecd9065809fd12/packages/core/src/di/injectable.ts#L117