¿Cuál es la diferencia entre @ViewChild y @ContentChild?

189

Angular 2 proporciona @ViewChild, @ViewChildren, @ContentChildy @ContentChildrendecoradores para consultar elementos descendientes de un componente.

¿Cuál es la diferencia entre los dos primeros y los dos últimos?

dibujó más
fuente
3
Este enlace me ayudó a blog.mgechev.com/2016/01/23/… después de leer las respuestas a continuación. Saludos :)
Gopinath Shiva

Respuestas:

256

Contestaré su pregunta usando la terminología de Shadow DOM y Light DOM (proviene de componentes web, vea más aquí ) En general:

  • Shadow DOM : es un DOM interno de su componente definido por usted (como creador del componente ) y oculto a un usuario final. Por ejemplo:
@Component({
  selector: 'some-component',
  template: `
    <h1>I am Shadow DOM!</h1>
    <h2>Nice to meet you :)</h2>
    <ng-content></ng-content>
  `;
})
class SomeComponent { /* ... */ }
  • DOM ligero : es un DOM que un usuario final de su componente suministra a su componente. Por ejemplo:
@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 { /* ... */ }

Entonces, la respuesta a tu pregunta es bastante simple:

La diferencia entre @ViewChildreny @ContentChildrenes que @ViewChildrenbusca elementos en Shadow DOM mientras los @ContentChildrenbusca en Light DOM.

alexpods
fuente
10
La entrada de blog blog.mgechev.com/2016/01/23/… de Minko Gechew tiene más sentido para mí. @ContentChildren son los hijos, insertados por proyección de contenido (los hijos entre <ng-content> </ng-content>). Desde el blog de Minkos: "Por otro lado, los elementos ** que se usan entre las etiquetas de apertura y cierre del elemento host de un componente dado se denominan * contenido hijos **". Aquí se describe Shadow DOM y encapsulación de vistas en Angular2: blog.thoughtram.io/angular/2015/06/29/… .
Westor
44
Para mí, parece que @TemplateChildren(en lugar de @ViewChildren) o @HostChildren(en lugar de @ContentChildren) habrían sido nombres mucho mejores, ya que en ese contexto todo lo que estamos hablando está relacionado con la vista, y el enlace wrt también está relacionado con el contenido.
superjos
35
@ViewChildren== tu propio hijo; @ContentChildren== hijo de otra persona
candidJ
107

Como su nombre indica, @ContentChildy @ContentChildrenlas consultas volverán directivas existentes en el interior del <ng-content></ng-content>elemento de la vista, mientras que @ViewChildy @ViewChildrensólo se ven en los elementos que están en su plantilla de vista directa.

dibujó más
fuente
Entonces, use @ViewChild (ren) a menos que tenga componentes en su vista, en cuyo caso recurrirá a @ContentChild (ren)?
Ben Taliadoros
31

Este video de Angular Connect tiene excelente información sobre ViewChildren, ViewChild, ContentChildren y ContentChild https://youtu.be/4YmnbGoh49U

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

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

Desde my-widgetla perspectiva de, comp-aes el ContentChildy comp-bes el ViewChild. CompomentChildreny ViewChildrendevuelve un iterable mientras que xChild devuelve una sola instancia.

mithun_daa
fuente
Esta es la mejor explicación. Gracias :)
Javeed
Hiciste un ejemplo claro y simple, pero la plantilla de MyWidget debería ser <comp-b><ng-content></ng-content></comp-b>correcta.
Arjel 01 de
1

Tomemos un ejemplo: tenemos un componente principal y un componente secundario y dentro del componente secundario un componente secundario pequeño.

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

Ahora puede tomar todos los elementos secundarios en el contexto del componente de inicio con @viewChildren porque estos se agregan directamente en la plantilla del componente de inicio. Pero, cuando intenta acceder al <small-child>elemento desde el contexto del componente secundario, no puede acceder a él porque no se agrega directamente dentro de la plantilla del componente secundario. Se agrega a través de la proyección de contenido en el componente secundario por componente de inicio. Aquí es donde entra @contentChild y puedes tomarlo con @contentChild.

La diferencia ocurre cuando intenta acceder a elementos de referencia en el controlador. Puede acceder a tomar todos los elementos que @viewChild agrega directamente a la plantilla del componente. Pero no puede tomar la referencia de elementos proyectados con @viewChild Para acceder al elemento proyectado, debe usar @contentChild.

dev verma
fuente