What's the difference between @ViewChild and @ContentChild?
Asked Answered
G

5

293

Angular 2 provides @ViewChild, @ViewChildren, @ContentChild and @ContentChildren decorators for querying a component's descendant elements.

What's the difference between the first two and the latter two?

Geostrophic answered 17/12, 2015 at 4:41 Comment(1)
This link helped me blog.mgechev.com/2016/01/23/… after reading the below answers. Cheers :)Univalent
E
352

I'll answer your question using Shadow DOM and Light DOM terminology (it have come from web components, see more here). In general:

  • Shadow DOM - is an internal DOM of your component that is defined by you (as a creator of the component) and hidden from an end-user. For example:
@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 - is a DOM that an end-user of your component supply into your component. For example:
@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 { /* ... */ }

So, the answer to your question is pretty simple:

The difference between @ViewChildren and @ContentChildren is that @ViewChildren look for elements in Shadow DOM while @ContentChildren look for them in Light DOM.

Emolument answered 17/12, 2015 at 6:11 Comment(6)
The blog entry blog.mgechev.com/2016/01/23/… from Minko Gechew makes more sense to me. @ContentChildren are the children, inserted by content projection (the children between <ng-content></ng-content> ) . From Minkos Blog: "On the other hand, **elements which are used between the opening and closing tags of the host element of a given component are called *content children **." Shadow DOM and view encapsulation in Angular2 is descibed here: blog.thoughtram.io/angular/2015/06/29/… .Hydrant
To me it sounds like @TemplateChildren (instead of @ViewChildren) or @HostChildren (instead of @ContentChildren) would have been much better names, as in such a context everything we're talking about is view-related, and w.r.t. binding is content-related too.Loney
@ViewChildren == your own child ; @ContentChildren == someone's else childJedda
@Jedda this is False today, in ContentChildren you have a flag that is {descendants: false} by default. So the equivalence is not correct.Pendragon
What about the @ViewChild and @ContentChild?Maidamaidan
@ContentChild looks the HTML defined in the use of your component tag, ex <my-component><div>THIS IS CONTENT CHILD</div></my-component>Furiya
G
169

As the name suggests, @ContentChild and @ContentChildren queries will return directives existing inside the <ng-content></ng-content> element of your view, whereas @ViewChild and @ViewChildren only look at elements that are on your view template directly.

Geostrophic answered 17/12, 2015 at 4:41 Comment(1)
So use @ViewChild(ren) unless you have components in your view in which case fall back to @ContentChild(ren)?Clotilda
B
54

This video from Angular Connect has excellent info about ViewChildren, ViewChild, ContentChildren and ContentChild https://youtu.be/4YmnbGoh49U

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

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

From my-widget's perspective, comp-a is the ContentChild and comp-b is the ViewChild. CompomentChildren and ViewChildren return an iterable while the xChild return a single instance.

Brimful answered 24/2, 2016 at 23:44 Comment(2)
This is the better explanation. Thanks :)Pastel
You made a clear and simple example, but MyWidget's template should be <comp-b><ng-content></ng-content></comp-b> right?Washbasin
S
16

Lets take a example, We have one home component and one child component and inside child component one small child component.

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

Now you can grab all children elements in context of home component with @viewChildren because these are directly added in template of home component. But, when you try to access <small-child> element from context of child component then you can't access it because it is not directly added within child component template. It is added through content projection into child component by home component. This is where @contentChild comes in and you can grab it with @contentChild.

The difference occur when you try to access elements reference in controller. You can grab all elements that are directly added into template of component by @viewChild. But you can't grab projected elements reference with @viewChild To access projected element you have to use @contentChild.

Sisneros answered 23/10, 2019 at 12:2 Comment(0)
C
6

Just rename ViewChildren to InternalChildren, and ContentChildren to ExternalChildren

Chequerboard answered 18/7, 2021 at 8:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.