0

So I have two Angular Components, a parent & a child. I want to do the following:

  1. Define an ng-template in the parent component that references child functions/variables
  2. Pass that template as a parameter to the child component, and
  3. Have the child component display this template using its own instance data.

App.Component (Parent)

import { Component } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {}
<reusable-component [customTemplate]="parentTemplate"></reusable-component>

<ng-template #parentTemplate>
  <p>Current color is {{currentColor}}</p>

  <button (click)="changeColorToRed()">
    CHANGE BACKGROUND COLOR TO RED
  </button>

  <button (click)="changeColorToGreen()">
    CHANGE BACKGROUND COLOR TO GREEN
  </button>
</ng-template>

Child Component (reusable-component)

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

@Component({
  selector: "reusable-component",
  templateUrl: "./reusable-component.component.html",
  styleUrls: ["./reusable-component.component.css"]
})
export class ReusableComponentComponent implements OnInit {
  @Input() public customTemplate!: TemplateRef<HTMLElement>;
  currentColor = "white";

  constructor() {}

  ngOnInit() {}

  changeColorToRed() {
    const red = "#FF0000";
    document.body.style.background = red;
    this.currentColor = "red";
  }
  changeColorToGreen() {
    const green = "#00FF00";
    document.body.style.background = green;
    this.currentColor = "green";
  }
}
<ng-container [ngTemplateOutlet]="customTemplate || defaultTemplate">
</ng-container>

<ng-template #defaultTemplate>
  Hello, zuko here!
</ng-template>

How do I provide my parent template with the functions/instance variables from that child Component?

Here's a Stackblitz with the whole project

treycrossley
  • 143
  • 1
  • 8

1 Answers1

1

Most of the things are fine. For passing data...

Let us first start defining the data to be passed in the Child Component

Child component TS

currentColor = "white";
constructor() {}

ngOnInit() {}

changeColorToRed() {
  const red = "#FF0000";
  document.body.style.background = red;
  this.currentColor = "red";
}
changeColorToGreen() {
  const green = "#00FF00";
  document.body.style.background = green;
  this.currentColor = "green";
}

data = { currentColor: this.currentColor, changeColorToRed: this.changeColorToRed, changeColorToGreen: this.changeColorToGreen };

Now, we pass the context containing the data to the template. Use *ngTemplateOutlet instead of [ngTemplateOutlet] to support chaining

Child component html

<ng-container *ngTemplateOutlet="customTemplate || defaultTemplate; context: data">
</ng-container>

Now, we use the let- attribute to receive the parameters in the parent

Parent component html

<reusable-component [customTemplate]="parentTemplate"></reusable-component>

<ng-template #parentTemplate let-currentColor="currentColor" let-changeColorToRed="changeColorToRed" let-changeColorToGreen="changeColorToGreen">
  <p>Current color is {{currentColor}}</p>

  <button (click)="changeColorToRed()">
    CHANGE BACKGROUND COLOR TO RED
  </button>

  <button (click)="changeColorToGreen()">
    CHANGE BACKGROUND COLOR TO GREEN
  </button>
</ng-template>

Stackblitz

T. Sunil Rao
  • 1,167
  • 5
  • 14
  • Thanks for your response!! Do I have to add every variable individually? We're working with a large file and it'd be much nicer to just get the component itself and all of its member variables in one swoop – treycrossley Feb 19 '21 at 22:06
  • You can wrap everything in an one object and use one `let-` attribute to receive that object – T. Sunil Rao Feb 19 '21 at 22:07
  • Do I have to do anything extra to get ViewChild to work with this template? In both the custom & default templates, I have a
    that I try to access in the child Component. I access it using @ViewChild('container', { static: false }) public readonly containerRef!: ElementRef; This always returns undefined in the custom template but works just fine in the defaultTemplate
    – treycrossley Feb 20 '21 at 04:04