ANDRII DATSENKO <ASDatsenko@luxoft.com>

TECHNICAL LEAD

May 17, 2017

 ANGULAR DI

 TAKE CONTROL OF DI

Dependency Injection is a technique where one object supplies the dependencies of another object

~Wikipedia

House

Bathroom

Kitchen

Garage

Car

Storage

CREATE A HOUSE

class House {
  private bathroom: Bathroom;
  private garage: Garage;
  private kitchen: Kitchen;
  constructor() {
    this.bathroom = new Bathroom();
    this.garage = new Garage();
    this.kitchen = new Kitchen();


  }
}

// what else?...

CREATE A GARAGE

class Garage {
  private car: Car;
  private storage: Storage;
  constructor() {
    this.car = new Car();
    this.storage = new Storage();

    
  }
}

Engine ?

Tools ?

// ...

CREATE A GARAGE

class Garage {
  private car: Car;
  private storage: Storage;
  constructor(car: Car, storage: Storage) {
    this.car = car;
    this.storage = storage;
  }
}

CREATE A HOUSE

class House {
  constructor(private bathroom: Bathroom,
              private garage: Garage,
              private kitchen: Kitchen,
              /* etc... */) {}
}

CREATION PROBLEM

const house = new House(
  new Bathroom(),
  new Garage(new Car(), new Storage()),
  new Kitchen()
);

Do we really need to know that?!

INJECTOR

const injector = new Injector([
  House,
  Bathroom,
  Garage,
  Kitchen,
  Car,
  Storage
]);

const house = injector.get(House);

ANGULAR DI

root injector

modules

components

configuration

ROOT INJECTOR

const injector = ReflectiveInjector.resolveAndCreate([Garage, Car, Storage]);
const garage = injector.get(Garage);
// Done for you
platformBrowserDynamic().bootstrapModule(AppModule);

MODULES

@NgModule({
  imports: [
    BrowserModule
  ],
  declarations: [
    AppComponent
  ],
  providers: [
    HomeService,
  ],
  exports: [
    BrowserModule
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

external providers

own providers

also a provider

re-export

COMPONENTS

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

import { HomeService } from './home.service';

@Component({
  selector: 'app-home',
  providers: [HomeService],
  template: `
    <h2>Home</h2>
  `
})
export class HomeComponent {

  constructor(homeService: HomeService) {
    this.home = homeService.getHome();
  }

}

own providers

CONFIGURATION

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

import { HomeService } from './home.service';
import { SmartHomeService } from './smart-home.service';

@Component({
  selector: 'app-home',
  providers: [{ 
    provide: HomeService, 
    useClass: SmartHomeService 
  }],
  template: `<h2>Home</h2>`
})
export class HomeComponent {
  constructor(homeService: HomeService) {
    this.home = homeService.getHome();
  }
}

override service

PROVIDER TYPES

class

value

factory

CLASS PROVIDERS

@Injectable()
class HomeService {
  constructor(private bathroom: Bathroom,
              private kitchen: Kitchen,
              private garage: Garage) {}

  getHome() {

  }
}

declare injection

providers: [ HomeService,
  // Creates two instances of `HomeService`
  { provide: OldHomeService, useClass: HomeService}
]

providers: [ HomeService,
  // alias to existing
  { provide: OldHomeService, useExisting: HomeService}
]

VALUE PROVIDERS

const defaultHome = <HomeService> {
  getHome: () => { return {}; }
};




[{ provide: HomeService, useValue: defaultHome }]

Non-class values???

VALUE PROVIDERS

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

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');

export interface AppConfig {
  apiHost: string;
}

export const appConfig: AppConfig = {
  apiHost: 'api.some.com'
};

// Configure
providers: [{ provide: APP_CONFIG, useValue: appConfig}]

// Inject
constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

Non-class values

FACTORY PROVIDERS

@Injectable()
export class HomeService {
  constructor(private car: Car, public isOwner: boolean) { }

  getCar() {
    return this.isOwner ? this.car : null;
  }
}
const homeServiceFactory = (userService: UserService) => {
  return new HomeService(userService.user.isOwner);
};

export let homeServiceProvider = { 
  provide: HomeService,
  useFactory: homeServiceFactory,
  deps: [UserService]
};
@Component({
  providers: [homeServiceProvider]
})
export class HomeComponent { }

INJECTION TREE

@SPECIAL

@Optional()

@Host()

@SkipSelft()

`null` when provider not found

stop searching for provider

skip current injector

LINKS

Q&A Time

ANDRII DATSENKO <ASDatsenko@luxoft.com>

TECHNICAL LEAD

May 17, 2017

ANGULAR DI

 TAKE CONTROL OF DI

Angular Dependency Injection

By Andrew Dacenko

Angular Dependency Injection

  • 1,038