web-dev-qa-db-fra.com

Différence entre @Self et @Host Angular 2+ Dependency Injection Decorators

Veuillez expliquer la différence entre @Self et @Host .

La documentation de l'API angular donne une idée. Mais ce n'est pas clair pour moi. L'exemple fourni pour Self utilise ReflectiveInjector pour illustrer l'utilisation.

Cependant, on utiliserait rarement, voire jamais, ReflectiveInjector dans le code d'application réel (probablement plus dans les tests). Pouvez-vous donner un exemple de l'endroit où vous utiliseriez @Self à la place de @Host en dehors de ces scénarios de test ??

16
Somo S.

tl; dr

Il semble que lorsque @Self Est utilisé, Angular recherchera uniquement une valeur liée à l'injecteur de composant pour l'élément sur lequel cette directive/composant existe.

Il semble que lorsque @Host Est utilisé, Angular recherchera une valeur qui est liée soit à l'injecteur de composant pour l'élément sur lequel cette directive/composant existe, soit à l'injecteur du composant parent . Angular appelle ce composant parent "Host".

Plus d'explication

Bien que les descriptions principales ne soient pas très utiles, elles ressemblent aux exemples de la documentation pour @ Self et @ Host font un travail décent pour clarifier comment ils sont utilisés et ce la différence est (copiée ci-dessous).

Lorsque vous essayez de comprendre cela, il peut être utile de se rappeler que lorsque l'injection de dépendance Angular essaie de résoudre une valeur particulière pour un constructeur, elle commence par rechercher dans l'injecteur le composant actuel, puis itère vers le haut via les injecteurs parents. En effet, Angular utilise des injecteurs hiérarchiques et permet l'héritage des injecteurs ancêtres.

Ainsi, lorsque la documentation @Host Indique qu'elle "spécifie qu'un injecteur doit récupérer une dépendance à partir de n'importe quel injecteur jusqu'à atteindre l'élément Host du composant actuel", cela signifie qu'il arrête cette itération ascendante tôt une fois qu'il atteint l'injecteur. lié au composant parent.

Exemple @Self ( source )

class Dependency {}

@Injectable()
class NeedsDependency {
  constructor(@Self() public dependency: Dependency) {}
}

let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
const nd = inj.get(NeedsDependency);

expect(nd.dependency instanceof Dependency).toBe(true);

inj = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = inj.resolveAndCreateChild([NeedsDependency]);
expect(() => child.get(NeedsDependency)).toThrowError();

Exemple @Host ( source )

class OtherService {}
class HostService {}

@Directive({selector: 'child-directive'})
class ChildDirective {
  logs: string[] = [];

  constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
    // os is null: true
    this.logs.Push(`os is null: ${os === null}`);
    // hs is an instance of HostService: true
    this.logs.Push(`hs is an instance of HostService: ${hs instanceof HostService}`);
  }
}

@Component({
  selector: 'parent-cmp',
  viewProviders: [HostService],
  template: '<child-directive></child-directive>',
})
class ParentCmp {
}

@Component({
  selector: 'app',
  viewProviders: [OtherService],
  template: '<parent-cmp></parent-cmp>',
})
class App {
}

Un exemple d'utilisation de @Self est important

Disons que vous avez une directive qui est utilisée pour modifier le comportement de nombreux types de composants; peut-être que cette directive fournit une sorte de support de configuration.

Cette directive est liée à de nombreux composants dans votre application et cette directive lie certains services dans sa liste providers. Les composants qui souhaitent utiliser cette directive pour se configurer dynamiquement injecteront le service qu'elle fournit.

Cependant, nous voulons nous assurer qu'un composant n'utilise que sa propre configuration et n'injecte pas accidentellement le service de configuration qui était destiné à un composant parent. Nous utilisons donc le décorateur @Self Pour indiquer à l'injection de dépendance d'Angular de ne considérer que le service de configuration fourni sur l'élément de ce composant.

14
Levi Lindsey

https://netbasal.com/exploring-the-various-decorators-in-angular-b208875b207c

Hôte:

@Host - Le décorateur @Host dit à DI de rechercher une dépendance dans n'importe quel injecteur jusqu'à ce qu'il atteigne l'hôte

Soi:

@Self - Le décorateur @Self dit à DI de ne rechercher une dépendance que de lui-même, donc il ne remontera pas dans l'arbre

voici un exemple:

https://plnkr.co/edit/UmpPTnzcRxgDc9Hn5I9G?p=preview

Comme vous le voyez, la directive MyDir utilise: @Self pour accéder à sa propre voiture Son composant '@Host Garage dependency @Optional @Host Sun dépendance qui n'est pas définie sur Host mais définie sur App. Puisqu'il n'est pas défini sur l'hôte - il sera nul

La sortie sera:

 parent component. 
  { "type": "child garage", 
    "car": { "model": "child car" }, 
    "Sun": null 
  }

Voici les composants et les fournisseurs:

  class Garage {
    car;
    type;
    Sun;

    constructor(type) {
      this.type=type;
    }
    setCar(car) {
      this.car = car;
    }
    setSun(Sun) {
      this.Sun = Sun;
    }
  }

  class Car {
    model;
    constructor(model) {
      this.model=model;
    }
  }

  class Sun { }

  @Directive({
    selector: '[myDir]',
    providers:[
      {provide: Car, useValue: new Car('child car')}
      {provide: Garage, useValue: new Garage('child garage')}
    ]
  })
  export class MyDir {
    constructor(@Self() private car: Car, @Host() private garage: Garage,
      @Optional() @Host() private Sun: Sun) {
       this.garage.setCar(this.car);
       this.garage.setSun(this.Sun);
    }
  }

  @Component({
    selector: 'parent',
    template: `
       parent component. {{garage|json}}
    `,
    providers:[
      {provide: Car, useValue: new Car('parent car')},
      {provide: Garage, useValue: new Garage('parent garage')}
    ]
  })
  export class Parent {
    childDep;
    constructor(private car: Car, private garage: Garage) {
    }
  }

  @Component({
    selector: 'my-app',
    template: `
  <parent myDir></parent>
    `,
    providers:[
      {provide: Car, useValue: new Car('app car')},
      {provide: Garage, useValue: new Garage('app garage')},
      {provide: Sun, useValue: 'Sun'}
    ]
  })
  export class App {
  }
3

Décorateur @Host() utilisé uniquement dans le contexte des composants et des directives. Il fait un travail similaire à celui d'un décorateur @Self() pour les services.

0
ktretyak