zoukankan      html  css  js  c++  java
  • [Angular] Control the dependency lookup with @Host, @Self, @SkipSelf and @Optional

    Very differently to AngularJS (v1.x), Angular now has a hierarchical dependency injector. That allows to specify service definitions as well as the service lifetime 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, @Self()@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: `
        <div style="border:1px;">
          <p *ngIf="logger === null">I don't have a logger</p>
          <button (click)="doLog()">write log</button>
        </div>
      `
       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');
        }
      }
    }
    // parent
    
    @Component({
      selector: 'app-root',
      template: `
        <h1>Angular Services</h1>
        <app-person></app-person>
      `,
      providers: [
        {
          provide: LoggerService,
          useFactory: loggerFactory('AppComponent')
        }
      ]
    })
    export class AppComponent {}

    SO in the end 'AppComponent ...' log message will appear in the console.

    @Self():

    Only using the provider for its own component.

    @Component({
      selector: 'app-person',
      template: `
        <div style="border:1px;">
          <p *ngIf="logger === null">I don't have a logger</p>
          <button (click)="doLog()">write log</button>
        </div>
      `
      // providers: [
      //   {
      //     provide: LoggerService,
      //     useFactory: loggerFactory('PersonComponent')
      //   }
      // ]
    })
    export class PersonComponent implements OnInit {
      constructor(
        @Self()
        @Optional()
        public logger: LoggerService
      ) {}
    
      ngOnInit() {}
    
      doLog() {
        if (this.logger) {
          this.logger.log('Message from PersonComponent');
        } else {
          console.log('sorry, no logger available');
        }
      }
    }

    So if PersonComponent has provider defined, it will use its own provider and will not continue searching parent component. 

    Often @Self can use togerther with @Optional, so if the provider is not defined, then set it to null.

    @Host:

    When we have directive, we might need to use @Host.

    @Component({
      selector: 'my-comp',
      ...
      providers: [
         MyService // Must have, other directive cannot find it, throw error.
      ]  
    })
    <my-comp highlighted />
    @Directive({
      selector: 'highlighted'
    })
    export class Hightlighted {
      // Use the provide inject directly into the host component
      constructor (@Host private myService: MyService) {}
    }

    Because we cannot ensure that host element must have the Injection, if not, Angular will throw error, to prevent that, @Host normally work with @Optional together.

    @Directive({
      selector: 'highlighted'
    })
    export class Hightlighted {
      // Use the provide inject directly into the host component
      constructor (@Optional @Host private myService: MyService) {}
    }

    Lesson

  • 相关阅读:
    第十次上机练习
    第七次作业
    第九次上机练习
    第八次上机练习
    第七次上机练习
    第六次作业
    第六次上机练习
    6.3
    5.28
    5.26
  • 原文地址:https://www.cnblogs.com/Answer1215/p/8856208.html
Copyright © 2011-2022 走看看