Very differently to AngularJS (v1.x), Angular now has a hierarchical dependency injector. That allows to specify service definitions as well as the at various levels in our application. Whenever a service is requested, Angular will walk up the component tree and search for a matching definition. While in most cases that's perfectly fine, often you may want to take control over the dependency lookup. In this lesson we will learn how, by applying @Host()
, @SkipSelf()
and @Optional()
.
@Optional:
When using @Optional, it set logger to null if the LoggerService is not provided instead of error out.
export class PersonComponent implements OnInit { constructor( @Optional() public logger: LoggerService ) {} ngOnInit() {} doLog() { if (this.logger) { this.logger.log('Message from PersonComponent'); } else { console.log('sorry, no logger available'); } }}
@SkipSelf:
If child component and parent component both using the same provider and we want to skip using child component's provider instead using parent's provider.
// Child@Component({ selector: 'app-person', template: `` providers: [ { provide: LoggerService, useFactory: loggerFactory('PersonComponent') } ]})export class PersonComponent implements OnInit { constructor( @SkipSelf() @Optional() public logger: LoggerService ) {} ngOnInit() {} doLog() { if (this.logger) { this.logger.log('Message from PersonComponent'); } else { console.log('sorry, no logger available'); } }}I don't have a logger
// parent@Component({ selector: 'app-root', template: `Angular Services
`, providers: [ { provide: LoggerService, useFactory: loggerFactory('AppComponent') } ]})export class AppComponent {}
SO in the end 'AppComponent ...' log message will appear in the console.
@Host():
Only using the provider for its own component.
@Component({ selector: 'app-person', template: `` // providers: [ // { // provide: LoggerService, // useFactory: loggerFactory('PersonComponent') // } // ]})export class PersonComponent implements OnInit { constructor( @Host() @Optional() public logger: LoggerService ) {} ngOnInit() {} doLog() { if (this.logger) { this.logger.log('Message from PersonComponent'); } else { console.log('sorry, no logger available'); } }}I don't have a logger
So if PersonComponent has provider defined, it will use its own provider and will not continue searching parent component.
Often @Host can use togerther with @Optional, so if the provider is not defined, then set it to null.