Skip to content

Feature: allow inject() to be used in constructor #25039

Closed

Description

@dawidgarus

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[x] 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

All the dependencies must be injected in constructor:

@Injectable()
export class MyService {
  constructor(private myOtherSerivice: MyOtherService) {}
}

Expected behavior

Allow to use inject() function when object is constructed, for example:

@Injectable()
export class MyService {
  private myOtherSerivice: MyOtherService = inject(MyOtherService);
}

Minimal reproduction of the problem with instructions

N/A

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

Imagine You have an abstract class which is extended by many services or components.
Then You want to change it which requires adding a new dependency.
When injecting via constructor You would have modify EVERY class that inherits it.

Environment


Angular version: 6.0.3

Activity

  1. kemsky commented on Jul 23, 2018

    @kemsky

    Actually it is possible to inject Injector and call its get-methods in your parent constructor.

  2. dawidgarus commented on Jul 23, 2018

    @dawidgarus
    Author

    @kemsky I know but it feels like a hack and You still need to inject Injector which may require a change in existing code base. With inject() approach it would be possible to create (as a library) decorator that uses reflections or create TypeScript transformer to achieve something like this:

    @Injectable()
    export class MyService {
      @Autowire() private myOtherSerivice: MyOtherService;
    }
    
  3. added
    featureLabel used to distinguish feature request from other issues
    area: coreIssues related to the framework runtime
    on Jul 23, 2018
  4. added this to the Backlog milestone on Jul 23, 2018
  5. trotyl commented on Jul 24, 2018

    @trotyl
    Contributor

    @kemsky This is more about consistency, using inject() is already supported at service constructor (with module-level provider):

    https://stackblitz.com/edit/angular-dergtr?file=src%2Fapp%2Fapp.component.ts

    This is indeed the correct behavior with current default provider semantics. Given this pattern is mostly about consumer-side usage, so it's should not be restricted to default provider, but also constructor of component, directive, pipe and directive provider should be supported as well.


    Given Ivy is going to be fully context-based (instead of call stack-based), I guess this will be supported in Ivy by default (haven't checked yet).

    EDIT: have a quick look at current Ivy codes, which should indeed work for most scenarios as long as powered by factory method function property of ngXXXDef, like:

    class SomeDirective {
      constructor(directive: DirectiveA) {}
    
      static ngDirectiveDef = defineDirective({
        type: SomeDirective,
        factory: () => new SomeDirective(directiveInject(DirectiveA))
      });
    }

    So the constructor would always share the same context of the factory.

    Given this is already the case in Ivy, should be reasonable to bring it (back?) to view engine.


    EDIT Again for Ivy: one thing possibly needs to be noticed is the inconsistency between inject and directiveInject, the private services like ElementRef, ViewContainerRef would not be available in inject (by default).

    Likely this behavior would be fixed by #23330, which would make inject() for directives different than inject() for application-wide services.

  6. trotyl commented on Jul 27, 2018

    @trotyl
    Contributor

    Seems a little hard for current view engine, I'd suggest just waiting for Ivy.

    @vicb Possibly add a fixed by Ivy tag for better tracking?

  7. gund commented on Jul 27, 2018

    @gund

    I think this should really be fixed because right now DI behaviour is inconsistent.

    If a service that is provided in @Component tries to inject ViewContainerRef it will not get it unless the component itself injects it.

    Repro: https://stackblitz.com/edit/angular-jxyoet

  8. trotyl commented on Jul 27, 2018

    @trotyl
    Contributor

    REMOVED.

  9. gund commented on Jul 27, 2018

    @gund

    @trotyl I do not think I am able to create a PR since I have not enough knowledge of how DI resolution mechanics are implemented.

    I hope that in Ivy this will be fixed tho (#23330).

  10. dawidgarus commented on Jul 27, 2018

    @dawidgarus
    Author

    @trotyl Correct me if I'm wrong, but wouldn't simple change in StaticInjector be sufficient?
    Just wrap get() method body with something like this:

    const former = setCurrentInjector(this);
    try {
      // body
    } finally {
      setCurrentInjector(former);
    }
  11. trotyl commented on Jul 30, 2018

    @trotyl
    Contributor

    @dawidgarus Static injector, module injector and node injector are mostly unrelated, and what used in a normal application are only module injector and node injector, not static injector.

    Also, the creation of Component, Directive, Pipe, NgModule is not the job of any injector.

  12. dawidgarus commented on Jul 30, 2018

    @dawidgarus
    Author

    Hopefully ivy will make everything simpler, because right now contributing to angular core by an outsider is, for all intents and purposes, impossible. Is there a public document which describes in details how angular internals work? For example what ngfactory file structure is exactly?

  13. trotyl commented on Jul 30, 2018

    @trotyl
    Contributor

    Hopefully ivy will make everything simpler

    This is going to be a built-in feature in Ivy and no need to worry about.

    because right now contributing to angular core by an outsider is, for all intents and purposes, impossible

    I guess it's not a good idea to ask another outsider then.

  14. angular-robot commented on Jun 4, 2021

    @angular-robot
    Contributor

    Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

    Find more details about Angular's feature request process in our documentation.

  15. angular-robot commented on Jun 25, 2021

    @angular-robot
    Contributor

    Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

    We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

    You can find more details about the feature request process in our documentation.

  16. alxhub commented on May 4, 2022

    @alxhub
    Member

    Closing as a duplicate of #34425 (they are the same underlying request)

  17. angelaki commented on May 5, 2022

    @angelaki
    Contributor

    Wow, injection via decorators sounds great! Just out of curiosity: since I still won't be able to get the cdr on demand I'd need to inject it (via decorator) in all of my components. Could this have a noticable performance impact? Or is it like No, the CDR exists anyway for every component, you wouldn't even be able to measure it?

  18. angular-automatic-lock-bot commented on Jun 5, 2022

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  19. locked and limited conversation to collaborators on Jun 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtimecore: difeatureLabel used to distinguish feature request from other issuesfeature: under considerationFeature request for which voting has completed and the request is now under consideration

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions