Quelle est la différence entre @ViewChild et @ContentChild?

189

Angulaire 2 fournit @ViewChild, @ViewChildren, @ContentChildet@ContentChildren décorateurs pour interroger les éléments descendants d'un composant.

Quelle est la différence entre les deux premiers et les deux derniers?

dessiné moore
la source
3
Ce lien m'a aidé blog.mgechev.com/2016/01/23/... après avoir lu les réponses ci-dessous. Cheers :)
Gopinath Shiva

Réponses:

256

Je répondrai à votre question en utilisant la terminologie Shadow DOM et Light DOM (elle provient de composants Web, voir plus ici ). En général:

  • Shadow DOM - est un DOM interne de votre composant qui est défini par vous (en tant que créateur du composant ) et caché à un utilisateur final. Par exemple:
@Component({
  selector: 'some-component',
  template: `
    <h1>I am Shadow DOM!</h1>
    <h2>Nice to meet you :)</h2>
    <ng-content></ng-content>
  `;
})
class SomeComponent { /* ... */ }
  • Light DOM - est un DOM qu'un utilisateur final de votre composant fournit à votre composant. Par exemple:
@Component({
  selector: 'another-component',
  directives: [SomeComponent],
  template: `
    <some-component>
      <h1>Hi! I am Light DOM!</h1>
      <h2>So happy to see you!</h2>
    </some-component>
  `
})
class AnotherComponent { /* ... */ }

Donc, la réponse à votre question est assez simple:

La différence entre @ViewChildrenet @ContentChildrenest que @ViewChildrenrechercher des éléments dans Shadow DOM et les @ContentChildrenrechercher dans Light DOM.

alexpods
la source
10
L'entrée de blog blog.mgechev.com/2016/01/23/… de Minko Gechew a plus de sens pour moi. @ContentChildren sont les enfants, insérés par projection de contenu (les enfants entre <ng-content> </ng-content>). Du blog Minkos: "D'autre part, ** les éléments qui sont utilisés entre les balises d'ouverture et de fermeture de l'élément hôte d'un composant donné sont appelés * enfants de contenu **." Shadow DOM et l'encapsulation de vue dans Angular2 sont décrits ici: blog.bientram.io/angular/2015/06/29/… .
westor
4
Pour moi, il semble que @TemplateChildren(au lieu de @ViewChildren) ou @HostChildren(au lieu de @ContentChildren) auraient été de bien meilleurs noms, car dans un tel contexte, tout ce dont nous parlons est lié à la vue, et la liaison wrt est également liée au contenu.
superjos
35
@ViewChildren== votre propre enfant; @ContentChildren== enfant de quelqu'un d'autre
candidJ
107

Comme son nom l'indique, @ContentChildet les @ContentChildrenrequêtes renverront les directives existant à l'intérieur de l' <ng-content></ng-content>élément de votre vue, tandis que @ViewChildet @ViewChildrenne regarderont que les éléments qui se trouvent directement sur votre modèle de vue.

dessiné moore
la source
Utilisez donc @ViewChild (ren) à moins que vous n'ayez des composants dans votre vue, auquel cas revenez à @ContentChild (ren)?
Ben Taliadoros
31

Cette vidéo d'Angular Connect contient d'excellentes informations sur ViewChildren, ViewChild, ContentChildren et ContentChild https://youtu.be/4YmnbGoh49U

@Component({
  template: `
    <my-widget>
      <comp-a/>
    </my-widget>
`
})
class App {}

@Component({
  selector: 'my-widget',
  template: `<comp-b/>`
})
class MyWidget {}

Du my-widgetpoint de vue de, comp-aest le ContentChildet comp-best le ViewChild. CompomentChildrenet ViewChildrenrenvoie un itérable tandis que le xChild renvoie une seule instance.

mithun_daa
la source
C'est la meilleure explication. Merci :)
Javeed
Vous avez donné un exemple clair et simple, mais le modèle de MyWidget devrait être <comp-b><ng-content></ng-content></comp-b>correct?
arjel
1

Prenons un exemple, nous avons un composant home et un composant enfant et à l'intérieur du composant enfant un petit composant enfant.

<home>
     <child>
           <small-child><small-child>
     </child>
</home>

Vous pouvez maintenant saisir tous les éléments enfants dans le contexte du composant home avec @viewChildren car ils sont directement ajoutés dans le modèle du composant home. Mais, lorsque vous essayez d'accéder à l' <small-child>élément à partir du contexte du composant enfant, vous ne pouvez pas y accéder car il n'est pas directement ajouté dans le modèle de composant enfant. Il est ajouté par projection de contenu dans le composant enfant par composant home. C'est là qu'intervient @contentChild et vous pouvez le récupérer avec @contentChild.

La différence se produit lorsque vous essayez d'accéder à la référence des éléments dans le contrôleur. Vous pouvez accéder à tous les éléments qui sont directement ajoutés au modèle de composant par @viewChild. Mais vous ne pouvez pas saisir la référence des éléments projetés avec @viewChild Pour accéder à l'élément projeté, vous devez utiliser @contentChild.

dev verma
la source