Tuesday 14 March 2023

What is TemplateRef and ViewContainerRef in angular with examples?

TemplateRef and ViewContainerRef are two important classes in Angular that are used to work with templates and dynamically add or remove components to the DOM.

TemplateRef is a class that represents an Angular template. It is used to create a view for a component, which can be added to the DOM when the component is rendered. Here's an example of how you might use TemplateRef:

import { Component, TemplateRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
    <ng-template #myTemplate let-name="name">
      <p>Hello {{ name }}!</p>
    </ng-template>

    <button (click)="showTemplate()">Show Template</button>
  `,
})
export class ExampleComponent {
  @ViewChild('myTemplate') myTemplate: TemplateRef<any>;

  showTemplate() {
    const context = {
      name: 'World'
    };
    this.viewContainerRef.createEmbeddedView(this.myTemplate, context);
  }

  constructor(private viewContainerRef: ViewContainerRef) {}
}

In this example, we have a component with a template that contains an ng-template element. The ng-template element defines a template that can be used to render a message that includes the value of the name variable.

The ExampleComponent class has a ViewChild property that is used to get a reference to the TemplateRef object that represents the ng-template element. When the user clicks the "Show Template" button, the showTemplate() method is called. This method uses the ViewContainerRef class to create an embedded view based on the TemplateRef object and passes in a context object that includes the value of the name variable.

When the embedded view is created, it is added to the DOM as a child of the ExampleComponent component. The view includes the message "Hello World!", which is derived from the value of the name variable passed into the context object.

ViewContainerRef is a class that represents a container for views. It is used to dynamically add or remove components to the DOM. Here's an example of how you might use ViewContainerRef:

import { Component, ComponentFactoryResolver, ViewContainerRef } from '@angular/core';
import { MyComponent } from './my-component.component';

@Component({
  selector: 'app-example',
  template: `
    <div #container></div>
    <button (click)="addComponent()">Add Component</button>
  `,
})
export class ExampleComponent {
  constructor(private viewContainerRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) {}

  addComponent() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
    const componentRef = this.viewContainerRef.createComponent(componentFactory);
    componentRef.instance.message = 'Hello World!';
  }
}

In this example, we have a component with a template that includes a div element that serves as a container for dynamically added components. The ExampleComponent class has a ViewContainerRef property that is used to get a reference to the container element.

When the user clicks the "Add Component" button, the addComponent() method is called. This method uses the ComponentFactoryResolver class to create a ComponentFactory object that represents the MyComponent component. It then uses the ViewContainerRef class to create a component based on the ComponentFactory and adds it to the container.

When the component is created, it is added to the DOM as a child of the container element. The component includes a message that is set to "Hello World!".

One real-life use case of TemplateRef is when we want to create reusable components that can display different content based on their context.

For example, let's say we want to create a tooltip component that displays additional information when the user hovers over a button. Instead of creating a separate component for each tooltip, we can define a single tooltip component that takes a TemplateRef as input.

The TemplateRef can contain the content that we want to display inside the tooltip. We can then pass this TemplateRef to the tooltip component as input, along with any other configuration options such as the tooltip position or style.

Using TemplateRef in this way allows us to create a flexible and reusable tooltip component that can be customized for different use cases. It also allows us to separate the content of the tooltip from the presentation logic, which can make the code easier to maintain and update over time.

here's an example of how we can use TemplateRef to create a reusable tooltip component in Angular:

1) First, we create a TooltipComponent that takes a TemplateRef as input:

import { Component, Input, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-tooltip',
  template: `
    <div class="tooltip" [ngStyle]="{ top: top, left: left }">
      <ng-container *ngTemplateOutlet="content"></ng-container>
    </div>
  `,
})
export class TooltipComponent {
  @Input() content: TemplateRef<any>;
  @Input() top: string;
  @Input() left: string;
}

2) In the template for our main component, we define a button with a tooltip:

<button (mouseenter)="showTooltip()" (mouseleave)="hideTooltip()">Hover me!</button>

<ng-container #tooltipContainer></ng-container>

<ng-template #tooltipContent>
  This is a tooltip!
</ng-template>
3)

We use the ViewChild decorator to get a reference to the ng-container element where we want to render the tooltip:

import { Component, ViewChild, TemplateRef } from '@angular/core';
import { TooltipComponent } from './tooltip.component';

@Component({
  selector: 'app-main',
  template: `
    <button (mouseenter)="showTooltip()" (mouseleave)="hideTooltip()">Hover me!</button>

    <ng-container #tooltipContainer></ng-container>

    <ng-template #tooltipContent>
      This is a tooltip!
    </ng-template>
  `,
})
export class MainComponent {
  @ViewChild('tooltipContainer', { read: ViewContainerRef }) tooltipContainer: ViewContainerRef;
  @ViewChild('tooltipContent') tooltipContent: TemplateRef<any>;

  tooltip: TooltipComponent;

  showTooltip() {
    const factory = this.componentFactoryResolver.resolveComponentFactory(TooltipComponent);
    this.tooltip = this.tooltipContainer.createComponent(factory).instance;
    this.tooltip.content = this.tooltipContent;
    this.tooltip.top = '50px';
    this.tooltip.left = '100px';
  }

  hideTooltip() {
    if (this.tooltip) {
      this.tooltipContainer.clear();
      this.tooltip = null;
    }
  }
}

4) In the showTooltip method, we create a new instance of the TooltipComponent and set its content, top, and left properties based on our configuration options.

5) We insert the content of the tooltip into the ng-container element using the ngTemplateOutlet directive:

<ng-container *ngTemplateOutlet="content"></ng-container>

6) Finally, in the hideTooltip() method, we remove the tooltip from the view by calling the clear method of the ViewContainerRef.

No comments:

Post a Comment