28

When should we use useExisting provider instead of useClass?

providers: [
{provide: Class1, useClass: Class1}, 
{provide: Class2, useExisting: Class2}]

REMARK: I have not found an exact question on SO. And for better indexing decided to create this specific one here, although I found this answers:

but would like to have more real examples

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176

3 Answers3

40

useExisting - create refrence to service example here
useClass - create new instance of service example here

izik f
  • 2,387
  • 2
  • 16
  • 17
30

Normally you get an instance per provider.

{provide: Class1, useClass: Class1}, 

is equivalent with just

Class1

With

{provide: Class1, useClass: Class3}, 

you can configure, that when a constructor requests Class1 Angular DI creates an instance of Class3 and passes it to the constructor.

{provide: Class2, useExisting: Class2}

doesn't result in an instance being created, but you can see this rather than an alias. If a constructor requests Class2, Angular DI looks for another provider for key Class2 and injects the instance from this Class2 provider. You can see useExisting like a reference to another provider or an alias.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Gunter, I don't get the explanation they've given here https://angular.io/guide/form-validation#adding-to-template-driven-forms for using `useExisting` rather than `useClass`. Can you please simplify this? – karthikaruna Oct 10 '17 at 11:57
  • @karthikaruna seems reasonable to me. I don't know what the problem is. A `useExisting` is just a redirect to another provider. – Günter Zöchbauer Oct 10 '17 at 12:25
  • The terms `Injectable` and `Provider` are synonymous and any class with a `decorator` is injectable. `useExisting: ForbiddenValidatorDirective` means use the provider `ForbiddenValidatorDirective` when asked for the provider with the key `NG_VALIDATORS`. Is this understanding from that context correct? – karthikaruna Oct 10 '17 at 12:32
  • 4
    `Injectable` and `Provider` are 2 different things. The injectable is a class DI can create an instance of, or a provided value that might be passed to a constructor. A provider is an entry in a registry of providers that DI maintains and that allows to lookup up providers by key (key is the type of a constructor parameter, a string or an `InjectToken`). The provider also holds information about how to "create" the injectable value/instance. DI looks up a provider, the provider provides the value, and DI passes the value (instance of an injectable or a value provided as-is) to a constructor. – Günter Zöchbauer Oct 10 '17 at 12:38
  • 3
    If you register `MyClass` as provider, this is the short form of `{ provide: MyClass, useClass: MyValue }` where `provide: MyClass` is the key a provider can be found with, and `useClass: MyValue` is a strategy passed to the provider that informs the provider what value it should provide for this key. `useClass: MyValue` means "use `new MyClass(...)`" and `useExisting: Foo` means, that DI needs to be consulted to lookup a provider for `Foo` and then inject the value this provider provides. – Günter Zöchbauer Oct 10 '17 at 12:40
  • Clean so far! One thing, in that context, I don't see that they have provided `ForbiddenValidatorDirective` by any of the ways you've stated above. How does the DI looks up `ForbiddenValidatorDirective` when asked for `NG_VALIDATORS` as `ForbiddenValidatorDirective` is not in the providers registry? – karthikaruna Oct 10 '17 at 13:02
  • Ok, now I understand what you mean. `ForbiddenValidatorDirective` is provided implicitly, like every component can inject it's parent component. I don't know the exact details in this case and don't have time to investigate. But it should give you an idea how this can work. – Günter Zöchbauer Oct 10 '17 at 13:13
  • 2
    Thank you so much for answering my naive questions man! You're great! – karthikaruna Oct 10 '17 at 13:16
  • Just one more naive question if you don't mind :). Where exactly in that context, is the provider `NG_VALIDATORS` asked for? – karthikaruna Oct 10 '17 at 13:23
  • Form controls inject applied validators to call them https://github.com/dart-lang/angular/search?utf8=%E2%9C%93&q=NG_VALIDATORS&type= – Günter Zöchbauer Oct 10 '17 at 13:31
  • How can we differentiate between the useclasses? like when you have `{provide: Class1, useClass: Class3}, ` and we still in some cases need `Class1` instead of `Class3`, how do we choose? – DFSFOT Apr 23 '19 at 13:35
  • There is no way to choose. One thing you can do is to decide where you put such a provider. If you add it to a lazy loaded module it overrides this for this module and other modules loaded by this module directly or transitively. If you add it do a component it overrides it for this component and all childs/descendants. Check the docs for more details. – Günter Zöchbauer Apr 23 '19 at 14:52
23

Angular creates factory for providers that will be used to instantiate provider.

I usually use the following table to understand the difference between types of providers.

enter image description here

As we can see in the picture above all of providers can be presented similar useFactory. When it's the time to get an instance of provider angular just calls factory function.

So for useClass angular resolves dependency from parameters array and then calls constructor with parameters while for useExisting angular gets existing resolved instance and returns it.

Use cases:

1) Don't expose full functionallity

{ provide: PublicApi, useExisting: PrivateImpl }

{ provide: MinimalLogger, useExisting: LoggerService }

{ provide: PlatformRef, useExisting: PlatformRef_ }

{ provide: ApplicationRef, useExisting: ApplicationRef_}

{ provide: Sanitizer, useExisting: DomSanitizer },

{ provide: Compiler, useExisting: JitCompiler }

2) Build tree

{ provide: Parent, useExisting: forwardRef(() => TreeViewComponent) }

3) Avoid circular dependency

{ provide: BaseComponent, useExisting: forwardRef(() => MyComponent) }

4) Provide common tokens

{ provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true }

{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EmailValidator),  multi: true }

{ provide: NgControl, useExisting: forwardRef(() => NgModel) }

{ provide: ControlContainer, useExisting: forwardRef(() => FormGroupDirective) }

{ provide: NG_VALUE_ACCESSOR, multi: true, useExisting: MyDatePickerComponent }

If we replace useExisting with useClass, then we’d be registering a new class instance

Shashank Vivek
  • 16,888
  • 8
  • 62
  • 104
yurzui
  • 205,937
  • 32
  • 433
  • 399
  • For multi providers construct, what if I forgot to put `multi: true` in some of the provider entries? – Glenn Mohammad Mar 11 '18 at 14:14
  • @GlennMohammad If you forgot to put multi: true then it will overrides the previously registered directives. – Deepak Patidar Apr 26 '18 at 06:17
  • @DeepakPatidar Actually, as of Angular 6, it will throw an error now: "Provider parse errors: Mixing multi and non multi provider is not possible for token InjectionToken_..." So that's pretty neat! :) – Glenn Mohammad Sep 16 '18 at 16:52