<ng-content> are all Angular elements used for rendering HTML, but what do they actually do? Why do we need three, and why can’t I just use regular HTML elements like divs? I’ve been burned and confused by these elements in the past so I endeavoured to try to understand the reasoning behind them.
<ng-template>s in a code base and thought they looked cool, so you put some HTML into one to try to look cool too, only to be completely baffled by why it wasn’t showing up on the screen or in the DOM? Only me? Cool…
The ng-template element is conceptually similar to the HTML
<template> element. From MDN:
So why would we ever want to write HTML that’s not rendered on page load? A really good use case is when creating reusable templates that can be used as needed and instantiated dynamically based on data or other input retrieved at runtime.
The same concepts apply to Angular’s
<ng-template>. If you put some HTML inside of an
<ng-template> tag, it not only won’t be on the screen, but it won’t be in the DOM either. Angular will replace the
<ng-template> tag and its contents with a comment. The key is that
<ng-template>s will only be displayed if used in partnership with a structural directive. We need something to tell Angular that we want to use this template. This can be easily accomplished using template variables.
So just putting a structural directive on an
<ng-template> isn’t enough to tell Angular we want to use the template, but we can use other elements to specify when they want to show our
<ng-template> by attaching our #template local template variable.
<ng-template> doesn’t itself get turned into a DOM element, only the contents are rendered to the DOM. So when the above example is rendered, the
<ng-template> wrapper element does not get turned into a DOM element in the same way a container div would; only the content text ends up on the DOM.
<ng-container> is an Angular grouping element that is similar to
<ng-container> in that it doesn’t represent a DOM element. The difference is that it will always be rendered, whereas an
<ng-template> will only be rendered if it is explicitly requested.
<ng-container>s are useful anywhere you need an extra container for some template elements, but don’t want to (or can’t) create a container such as a div to hold them with due to syntax or style constraints.
For example, it is not allowed in Angular to put two structural directives on the same element. If you needed to loop through an array and display a
<tr> for each element, but only if a different condition was met, you may want to put both an *ngFor and *ngIf on the
<tr> element. Angular does not allow this, however, and wrapping the
<tr> in a
<div> to hold one of the structural directives is not valid HTML. The utility of
<ng-container> shines here, where we can use the
<ng-container> to hold a structural directive and contain the
<tr></span> without breaking the HTML layout.
And despite the fact that the
<ng-container> will always be rendered, even if the item doesn’t meet the inner condition, no extra elements will be added to the DOM since the
<ng-container> alone doesn’t represent a DOM element.
We can bring together the
<ng-template> elements using the *ngTemplateOutlet structural directive. This directive allows us to instantiate a
<ng-template> anywhere on the page.
Placing this directive on an
<ng-container> element allows us to place an instance of a template wherever we need it. *ngTemplateOutlet can also take a context object as input, which becomes available for binding by the local template let declarations.
<ng-container>, andngTemplateOutlet are all used (sometimes in combination) to instantiate and place HTML templates in a view, and
<ng-content> serves a similar role in a slightly different way.
<ng-content> is used for projecting content into components. Any component that will accept other components between its opening and closing tags will use an
<ng-content> to indicate where that content should be placed.
If we create a SomeComponent component, we can indicate that it can take projected content by using the
<ng-content> tag to indicate where the projected content should go.
And then wherever we use SomeComponent, we can insert any template elements between its opening and closing tags as the projected content.