Some History
In Web Components there *used* to be a property on components called <content>
which was used inside of Shadow DOM as an insertion point. This has since been deprecated in favor of the <slot>
element; see reference on MDN. They are very similar in content, both allowing for the projection of DOM into a certain point.
ng-content specification
The spec for <content>
calls for the web component to actually initialize even if the content is not projected into the DOM. This is important to note because Angular follows this standard. That means when you use <ng-content>
even if you *ngIf
the content tag to only show when something is activated, the nested component will still initialize. The reason is ng-content
does not actually produce content, it simply projects existing content. To learn more about this, see the Github Issue on the Angular project.
You can see an example of this in this plunkr.
Use Case
If you build something like a tab’s component, something like this:
and a tab component like:
You can see in this example, the <ng-content>
is toggle off by *ngIf
when the tab is not active. Even though its behind that *ngIf
, the components nested in my tab will still initialize but not be inserted into the DOM. This can cause a few different problems:
- Components relying on DOM calculations such as sizing/animations will not be measured correctly since there is no DOM yet.
- In situations where you have large amounts of nested components inside <ng-content>
it can be a performance issue.
Solution
Now that we understand the problem and the why, how do we fix this? Its actually pretty simple, inside your content you are projecting, you just need to add a *ngIf
. So in the situation of the tabs, you could do something like:
<my-tabs>
<tab title=”Foo” #fooTab>
<div *ngIf=”footTab.active”>
…You Content…
</div>
</tab>
</my-tabs>
Wrapping Up
While this is can be unexpected, Angular is actually following the specification for web components ( which I think is ideal ). The solution is relatively simple to implement but you need to know about it.