Skip to content
intermediate Phase 5 · Services and Dependency Injection

Providers, Tokens, and multi Providers

Configure how the injector produces values for abstract tokens.

45m
0 problems
Topic Progress 0%

Provider Types

Angular's DI system supports multiple provider types for different scenarios.

useValue — Static Values

import { InjectionToken } from '@angular/core';

export const API_URL = new InjectionToken<string>('API_URL');

@NgModule({
  providers: [
    { provide: API_URL, useValue: 'https://api.example.com' },
  ],
})
export class AppModule {}

useFactory — Dynamic Values

export function loggerFactory(isDev: boolean): LoggerService {
  return isDev ? new ConsoleLogger() : new RemoteLogger();
}

@NgModule({
  providers: [
    { provide: IS_DEV, useValue: true },
    {
      provide: LoggerService,
      useFactory: loggerFactory,
      deps: [IS_DEV],
    },
  ],
})
export class AppModule {}

useClass — Alternative Implementations

@Injectable()
abstract class StorageService {
  abstract get(key: string): string | null;
  abstract set(key: string, value: string): void;
}

@Injectable()
class LocalStorageService extends StorageService {
  get(key: string): string | null {
    return localStorage.getItem(key);
  }
  set(key: string, value: string): void {
    localStorage.setItem(key, value);
  }
}

@NgModule({
  providers: [
    { provide: StorageService, useClass: LocalStorageService },
  ],
})
export class AppModule {}

useExisting — Aliasing

@NgModule({
  providers: [
    LoggerService,
    { provide: OldLoggerService, useExisting: LoggerService },
  ],
})
export class AppModule {}

Provider Comparison

Type Use Case
useValue Constants, configuration objects
useFactory Values that depend on other services
useClass Swappable implementations
useExisting Aliasing one token to another

InjectionToken and multi Providers

InjectionToken creates typed keys for values that are not classes. The multi option collects multiple providers under one token.

InjectionToken

import { InjectionToken } from '@angular/core';

export const HTTP_INTERCEPTORS = new InjectionToken<HttpInterceptor[]>('HTTP_INTERCEPTORS');
export const API_URL = new InjectionToken<string>('API_URL');
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');

Why Not Just Use Strings?

// BAD: String tokens can collide
{ provide: 'apiUrl', useValue: 'https://api.example.com' }

// GOOD: InjectionToken is type-safe and collision-proof
{ provide: API_URL, useValue: 'https://api.example.com' }

multi: true — Multiple Providers

import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
  ],
})
export class AppModule {}

With multi: true, each provider is added to an array rather than replacing the previous one. The injector returns an array of all registered interceptors.

Custom Multi-Provider Token

export const VALIDATORS = new InjectionToken<ValidatorFn[]>('VALIDATORS');

export function requiredValidator(control: AbstractControl): ValidationErrors | null {
  return control.value ? null : { required: true };
}

export function minLengthValidator(control: AbstractControl): ValidationErrors | null {
  return control.value?.length >= 3 ? null : { minLength: true };
}

@NgModule({
  providers: [
    { provide: VALIDATORS, useValue: requiredValidator, multi: true },
    { provide: VALIDATORS, useValue: minLengthValidator, multi: true },
  ],
})
export class AppModule {}

Provider Resolution Order

When multiple providers exist for the same token:

  1. Component-level providers (highest priority)
  2. Module-level providers
  3. Root-level providers (lowest priority)

The last registered provider wins (unless multi: true).

Quiz

1. What is an InjectionToken used for?

Question 1 options

2. What does multi: true do in a provider?

Question 2 options

3. Which provider type should you use for a value that depends on other services?

Question 3 options

Flashcards

Question

What is an InjectionToken?

Answer

A typed key for non-class dependencies. Prevents string collisions and provides type safety.

Question

What does multi: true do?

Answer

Collects multiple providers under one token into an array. Used for HTTP interceptors and validators.

Question

Which provider type for dynamic values?

Answer

useFactory — accepts a function with deps array and returns the computed value.

Revision Notes

Key Takeaways

  • 1. InjectionToken creates type-safe keys for non-class values
  • 2. useFactory handles values that depend on other services
  • 3. multi: true collects providers into an array
  • 4. Provider resolution: component > module > root

Interview Tips

  • • Explain why InjectionToken is better than string tokens
  • • Be ready to describe the multi-provider pattern for interceptors
  • • Mention useFactory for environment-specific configuration

Cheat Sheet

Providers and Tokens Cheat Sheet

Provider types:

{ provide: TOKEN, useValue: value }
{ provide: TOKEN, useFactory: fn, deps: [DEP] }
{ provide: TOKEN, useClass: Class }
{ provide: TOKEN, useExisting: OtherToken }

InjectionToken:

export const API_URL = new InjectionToken<string>('API_URL');

Multi-provider:

{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }

Continue Learning