Angular

Dependency Injection

Chau Tran

twitter.com/@nartc1410

github.com/nartc

Agenda

Syntax

export class SomeRepository {}

export class SomeService {
	constructor(private someRepository: SomeRepository) {}
}

export class SomeClass {
	constructor(private someService: SomeService) {}
}
export class SomeRepository {}

export class SomeService {
  	@Autowired()
  	private someRepository: SomeRepository;
}

export class SomeClass {
  	@Autowired()
	private someService: SomeService;
}
@Injectable({ providedIn: 'root' })
export class OneService {}

@Injectable()
export class TwoService {}

@Component({
  /* ... */,
  standalone: true,
  providers: [TwoService]
})
export class SomeComponent {
  constructor(
    private oneService: OneService,
    private twoService: TwoService
  ) {}
}

Injector

bootstrapApplication(AppComponent);
bootstrapApplication(AppComponent);
bootstrapApplication(AppComponent);

RootInjector

PlatformInjector

bootstrapApplication(AppComponent);

RootInjector

PlatformInjector

providedIn: 'root'

providedIn: 'platform'

import { bootstrapApplication } from '@angular/platform-browser';

bootstrapApplication(AppComponent);

RootInjector

PlatformInjector

providedIn: 'root'

providedIn: 'platform'

import { bootstrapApplication } from '@angular/platform-browser';

bootstrapApplication(AppComponent);

RootInjector

PlatformInjector

providedIn: 'root'

providedIn: 'platform'

import { bootstrapApplication } from '@angular/platform-browser';

bootstrapApplication(AppComponent);

RootInjector

PlatformInjector

providedIn: 'root'

providedIn: 'platform'

NullInjector

ElementInjector

EnvironmentInjector

ElementInjector

(or NodeInjector)

ElementInjector

(or NodeInjector)

@Component({
  providers: [/* here */]
})

ElementInjector

(or NodeInjector)

@Component({
  providers: [/* here */]
})
@Component({
  viewProviders: [
    /* here */
  ]
})

ElementInjector

(or NodeInjector)

@Component({
  providers: [/* here */]
})
@Component({
  viewProviders: [
    /* here */
  ]
})
@Directive({
  providers: [/* here */]
})

ElementInjector

(or NodeInjector)

@Component({
  providers: [/* here */]
})
@Component({
  viewProviders: [
    /* here */
  ]
})
@Directive({
  providers: [/* here */]
})

Component Tree

ElementInjector

EnvironmentInjector

EnvironmentInjector

EnvironmentInjector

ModuleInjector

EnvironmentInjector

EnvironmentInjector

Outside of Component Tree

EnvironmentInjector

Outside of Component Tree

EnvironmentInjector

Outside of Component Tree

RootInjector

PlatformInjector

NullInjector

EnvironmentInjector

@Injectable({ providedIn: '...' })
@Injectable({ providedIn: '...' })

EnvironmentInjector

@Injectable({ providedIn: '...' })
@Injectable({ providedIn: '...' })
bootstrapApplication(AppComponent, {
  providers: [/* ... */]
})

EnvironmentInjector

@Injectable({ providedIn: '...' })
@Injectable({ providedIn: '...' })
bootstrapApplication(AppComponent, {
  providers: [/* ... */]
})
const routes: Route[] = [
  {
    /* ... */
    providers: [/* ... */],
    /* ... */
  }
]

EnvironmentInjector

@Injectable({ providedIn: '...' })
@Injectable({ providedIn: '...' })
bootstrapApplication(AppComponent, {
  providers: [/* ... */]
})
const routes: Route[] = [
  {
    /* ... */
    providers: [/* ... */],
    /* ... */
  }
]
@NgModule({
  providers: [/* ... */]
})

Injectable

@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'any' })
export class AnyService {}

@Component({})
export class AChildComponent {
  constructor(private anyService: AnyService) {}
}

@Component({
  imports: [AChildComponent]
})
export class AComponent {
  constructor(private anyService: AnyService) {}
}

@Component({})
export class BComponent {
  constructor(private anyService: AnyService) {}
}
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'any' })
export class AnyService {}

@Component({})
export class AChildComponent {
  constructor(private anyService: AnyService) {}
}

@Component({
  imports: [AChildComponent]
})
export class AComponent {
  constructor(private anyService: AnyService) {}
}

@Component({})
export class BComponent {
  constructor(private anyService: AnyService) {}
}

export const routes: Route[] = [
  {
    path: 'a',
    loadComponent: () => import('./a.component').then(mod => mod.AComponent),
  },
  {
    path: 'b',
    loadComponent: () => import('./b.component').then(mod => mod.BComponent),
  }
]
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Component({
  providers: []
})
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Component({
  providers: []
})
@Directive({
  providers: []
})
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Component({
  providers: []
})
@Directive({
  providers: []
})
@Component({
  viewProviders: []
})
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()
@Injectable({ providedIn: 'root' })
@Injectable({ providedIn: 'platform' })
@Injectable({ providedIn: 'any' })
@Injectable()

Inject, InjectionToken

InjectionToken

Inject, InjectionToken

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

Inject, InjectionToken

export const API_URL = new InjectionToken<string>('API Base URL');
@Inject(API_WINDOW) private apiUrl: string

Inject, InjectionToken

export const API_URL = new InjectionToken<string>('API Base URL');
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Inject, InjectionToken

export const WINDOW = new InjectionToken<Window>('Window');
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Inject, InjectionToken

export const WINDOW = new InjectionToken<Window>('Window', {
  factory: () => {
    
  }
});
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Inject, InjectionToken

export const WINDOW = new InjectionToken<Window>('WIndow', {
  factory: () => {
    const document = inject(DOCUMENT);
  }
});
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Inject, InjectionToken

export const WINDOW = new InjectionToken<Window>('Window', {
  factory: () => {
    const document = inject(DOCUMENT);
    return document?.defaultView || null;
  }
});
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Inject, InjectionToken

export const WINDOW = new InjectionToken<Window>('Window', {
  providedIn: '...', // default is 'root'
  factory: () => {
    const document = inject(DOCUMENT);
    return document?.defaultView || null;
  }
});
@Inject(API_WINDOW) private apiUrl: string
providers: [{ provide: API_URL, useValue: environment.apiUrl }]

Provider

Provider

Provider

@Injectable({ providedIn: '...' })

Provider

@Injectable()

Provider

@Injectable()
@Component({ providers: [] })
@Component({ viewProviders: [] })
@Directive({ providers: [] })
const route = { providers: [] }

Provider

@Injectable()
interface Provider {
  provide: InjectionToken | string;
  useClass?: Type;
  useFactory: (...args: any[]) => any;
  useExisting?: Type;
  useValue?: any;
}

Provider

@Injectable()
@Component({
  providers: [SomeStore]
})
export class SomeComponent {}

Provider

@Injectable()
@Component({
  providers: [
    // SomeStore
    { provide: SomeStore, useClass: SomeStore }
  ]
})
export class SomeComponent {}

Provider

@Injectable()
@Component({
  providers: [
    // SomeStore
    { provide: SomeStore, useExisting: SomeStore }
  ]
})
export class SomeComponent {}

@Component({
  providers: [SomeStore],
  imports: [SomeComponent]
})
export class SomeParentComponent {}

Provider

@Injectable()
{
  provide: API_URL,
  useValue: environment.apiUrl
}

Provider

@Injectable()
{
  provide: API_URL,
  useFactory: () => {
    return environment.apiUrl
  },
}

Provider

@Injectable()
{
  provide: API_URL,
  useFactory: (configurationService: ConfigurationService) => {
    return configurationService.apiUrl;
  },
  deps: [ConfigurationService]
}

Resolution Modifier

Resolution Modifier

Resolution Modifier

@Optional()
@SkipSelf()
@Self()
@Host()

inject()

Q/A

Angular Dependency Injection

By Chau Tran

Angular Dependency Injection

  • 448