web-dev-qa-db-fra.com

Obtenir une référence au composant enfant dans le composant parent

Dans Angular 2, j'ai un composant qui a un composant enfant. Cependant, je souhaite acquérir une copie de ce composant enfant à utiliser dans le parent, pour appeler ses fonctions ou autre.

J'ai découvert que je pouvais utiliser des variables locales, ce qui me permettrait d'utiliser le composant dans le modèle. Cependant, je ne l’utilise pas uniquement dans le modèle, je souhaite l’utiliser dans le code même du composant.

J'ai trouvé un moyen de faire cela, voici le code enfant:

//our child
import {Component, OnInit, EventEmitter} from 'angular2/core'

@Component({
  selector: 'my-child',
  providers: [],
  template: `
    <div>
      <h2>Child</h2>

    </div>
  `,
  directives: [],
  outputs: ['onInitialized']
})

export class Child implements OnInit{

  onInitialized = new EventEmitter<Child>();

  constructor() {
    this.name = 'Angular2'
  }

  ngOnInit() {
    this.onInitialized.emit(this);
  }
}

Parent:

//our root app component
import {Component} from 'angular2/core'
import {Child} from './child'

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <my-child (onInitialized)="func($event)"></my-child>
    </div>
  `,
  directives: [Child]
})
export class App {
  constructor() {
    this.name = 'Angular2'
  }

  func(e) {
    console.log(e)

  }
}

Je l'ai implémenté ici dans ce plunker . Mais cela ressemble à un bidouillage.

N'y a-t-il pas un moyen plus simple d'attacher le composant à une variable de son parent?

38

Vous pouvez utiliser ViewChild

<child-tag #varName></child-tag>

@ViewChild('varName') someElement;

ngAfterViewInit() {
  someElement...
}

varName est une variable de modèle ajoutée à l'élément. Vous pouvez également interroger par type de composant ou de directive.

Il existe des alternatives telles que ViewChildren , ContentChild , ContentChildren .

@ViewChildren Peut également être utilisé dans le constructeur.

constructor(@ViewChildren('var1,var2,var3') childQuery:QueryList)

L'avantage est que le résultat est disponible plus tôt.

Voir aussi http://www.bennadel.com/blog/3041-constructor-vs-property-querylist-injection-in-angular-2-beta-8.htm pour certains avantages/inconvénients de en utilisant le constructeur ou un champ.

Remarque: @Query() est le prédécesseur déconseillé de @ContentChildren()

Mettre à jour

Query n'est actuellement qu'une classe de base abstraite. Je n'ai pas trouvé si elle était utilisée https://github.com/angular/angular/blob/2.1.x/modules/@angular/core/src/metadata/di.ts#L145

67
Günter Zöchbauer

Vous devez exploiter le @ViewChild _ décorateur pour référencer le composant enfant du composant parent par injection:

import { Component, ViewChild } from 'angular2/core';  

(...)

@Component({
  selector: 'my-app',
  template: `
    <h1>My First Angular 2 App</h1>
    <child></child>
    <button (click)="submit()">Submit</button>
  `,
  directives:[App]
})
export class AppComponent { 
  @ViewChild(Child) child:Child;

  (...)

  someOtherMethod() {
    this.searchBar.someMethod();
  }
}

Voici la version mise à jour: http://plnkr.co/edit/mrVK2j3hJQ04n8vlXLXt?p=preview .

Vous pouvez remarquer que le @Query paramètre de décorateur pourrait également être utilisé:

export class AppComponent { 
  constructor(@Query(Child) children:QueryList<Child>) {
    this.childcmp = children.first();
  }

  (...)
}
6
Thierry Templier

Vous pouvez réellement aller avec ViewChild API ...

parent.ts

<button (click)="clicked()">click</button>

export class App {
  @ViewChild(Child) vc:Child;
  constructor() {
    this.name = 'Angular2'
  }

  func(e) {
    console.log(e)

  }
  clicked(){
   this.vc.getName();
  }
}

child.ts

export class Child implements OnInit{

  onInitialized = new EventEmitter<Child>();
  ...  
  ...
  getName()
  {
     console.log('called by vc')
     console.log(this.name);
  }
}
2
micronyks