假设我在app.config.ts里定义了一个interface AppConfig和一个对象HERO_DI_CONFIG, 我想将后者注入到一个类的构造函数里去:
export interface AppConfig { apiEndpoint: string; title: string; } import { InjectionToken } from '@angular/core'; export const APP_CONFIG = new InjectionToken<AppConfig>('app.config'); export const HERO_DI_CONFIG: AppConfig = { apiEndpoint: 'api.heroes.com', title: 'Dependency Injection' };
使用InjectionToken新建一个token,类型参数为AppConfig,单引号里的app.config是injection token的描述信息。
在NgModule里使用useValue注入:在需要使用这个依赖的地方,将token APP_CONFIG传入@Inject:
最后的效果:
在控制反转中,”控制“是指对程序流程的控制,”反转“则是将控制权从程序员的手里反转到了外层框架。
@optional修饰符
@Component({ selector: 'app-notification', templateUrl: './notification.component.html', styleUrls: ['./notification.component.less'] }) export class NotificationComponent implements OnInit { constructor(@Optional() private msg: MessageService) {} ngOnInit() { this.msg.send(); } }
如果无法注入,msg被Angular解析成null,而不会抛出错误。
@Self@SkipSelf一个例子:在父组件中定义了一个服务:ParentMessageService
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class ParentMessageService { constructor() {} send() { console.log('come from parent'); } } @Component({ selector: 'app-container', templateUrl: './container.component.html', styleUrls: ['./container.component.less'], providers: [ { provide: MessageService, useClass: ParentMessageService } ] }) export class ContainerComponent implements OnInit { constructor() {} ngOnInit() {} }
子组件中,我们已提供了服务,但是注入时使用了 @SkipSelf() 修饰符
@Component({ selector: 'app-notification', templateUrl: './notification.component.html', styleUrls: ['./notification.component.less'], providers: [ { provide: MessageService, useClass: NewMessageService } ] }) export class NotificationComponent implements OnInit { constructor(@SkipSelf() private msg: MessageService) {} ngOnInit() { this.msg.send(); } }
最终,Angular会注入父组件的服务实例:ParentMessageService
什么是 Angular 的 ElementInjector?
这个概念和 Angular 多级注入器有关。Angular creates ElementInjectors implicitly for each DOM element. Angular 会为每个 DOM 元素隐式创建 ElementInjector。
Providing a service in the @Component() decorator using its providers or viewProviders property configures an ElementInjector.
当我们在 Component 里定义 providers 时,我们就已经配置了一个 ElementInjector.
@Component({ ... providers: [{ provide: ItemService, useValue: { name: 'lamp' } }] }) export class TestComponent
6/articlWhen you provide services in a component, that service is available via the ElementInjector at that component instance.
通过 ElementInjector,我们配置在 Component 里的服务,能够被组件实例使用到。
组件是一种特殊类型的指令,这意味着 @Directive() 具有 providers 属性,@Component() 也同样如此。 这意味着指令和组件都可以使用 providers 属性来配置提供者。当使用 providers 属性为组件或指令配置提供者时,该提供程商就属于该组件或指令的 ElementInjector。同一元素上的组件和指令共享同一个注入器。