Any directive, component, and element which is part of component template is accessed as ViewChild. Whereas, any element or component which is projected inside <ng-content> is accessed as ContentChild.
ViewChild is used to select an element from component's template while ContentChild is used to select projected content.
Another critical difference is that @ViewChild returns a single native DOM element as a reference, while the @ViewChildren decorator returns the list of different native DOM elements in the form of QueryList , which contains the set of elements.
The ContentChild & ContentChildren are decorators, which we use to Query and get the reference to the Projected Content in the DOM. Projected content is the content that this component receives from a parent component. The ContentChild & ContentChildren is very similar to the ViewChild & ViewChildren.
I'll answer your question using Shadow DOM and Light DOM terminology (it have come from web components, see more here). In general:
@Component({
selector: 'some-component',
template: `
<h1>I am Shadow DOM!</h1>
<h2>Nice to meet you :)</h2>
<ng-content></ng-content>
`;
})
class SomeComponent { /* ... */ }
@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.
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.
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.
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 access 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.
Just rename ViewChildren to InternalChildren, and ContentChildren to ExternalChildren
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With