Angular ViewRef, ViewContainerRef, TemplateRef and ElementRef are very important to understand. We always use them at least indirectly.

ViewRef

A view in Angular is represented by a ViewRef.

this.embeddedViewRef = this.templateRef.createEmbeddedView({ $implicit: 'Angular', dateNow: new Date() });
this.viewContainerRef.insert(this.embeddedViewRef);

For example we can create a component and append it outside of the RootComponent (AppComponent) and still attach it to the change detection cycles.

const modalRef = createComponent(ModalComponent, { environmentInjector: this.injector });
document.body.appendChild(modalRef.location.nativeElement);

// This includes the component into change detection cycles. (ApplicationRef)
this.applicationRef.attachView(modalRef.hostView);

ViewContainerRef

A ViewContainer represents a collection of ViewRef items. We can obtain a ViewContainerRef for every element in the template through dependency injection in a component, a directive or a @ViewChild({ read: ViewContainerRef }) decorated property in a component / directive.

ViewContainerRef will NOT hold children inside itself. It will insert a ViewRef AFTER itself as a sibling.
(The router-outlet works like that as well).

TemplateRef

A TemplateRef represents an <ng-template />.

<ng-template let-name let-date="dateNow">{{date}} - Hello {{name}}!</ng-template>

An <ng-template /> itself will not do anything at all.
We need a ViewContainerRef to insert the template somewhere.

this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef, { $implicit: 'Angular', dateNow: new Date().toString().slice(0, 10) });

Which is a shorthand for:

this.embeddedViewRef = this.templateRef.createEmbeddedView({ $implicit: 'Angular', dateNow: new Date().toString().slice(0, 10) });
this.viewContainerRef.insert(this.embeddedViewRef);

The template will then be rendered as following.

Mon Jul 24 - Hello Angular!

To remove the template:

this.embeddedViewRef.destroy();

Indirectly we do the same thing with an ngIf directive all the time. ngIf internally does exactly that.

ElementRef

An ElementRef is a wrapper around a DOM element (nativeElement).

this.elementRef.nativeElement.style.backgroundColor = 'yellow';

// Or better by using the Renderer2:
this.renderer.setStyle(this.elementRef.nativeElement, 'backgroundColor', 'yellow');

Why we should use Renderer2?

Renderer2 encapsulates the DOM access which allows us to intercept it's behavior or even render something other than DOM. This can be useful for different platforms like SSR / Server-Side Rendering. It also makes testing easier by mocking Renderer2.