Search code examples
typescriptangular7viewchildng-template

How to reuse an ngTemplate which wraps a Viewchild that updates it's content


I want to reuse an ng-template with a viewchild that changes dynamically and have it update in all the places I reuse the ng-template. However it doesnt update in all places.

It works when i make the content of the ng-template static like this:

<h2>Position 1</h2>
<ng-container [ngTemplateOutlet]="statusTemplate"></ng-container>
<h2>Position 2</h2>
<ng-container [ngTemplateOutlet]="statusTemplate"></ng-container>
<ng-template #statusTemplate>
  <h3>Saved</h3>
</ng-template>

that outputs the following HTML:

enter image description here

However when i make the h3 inside the ng-template a view child and try to update it dynamically it doesn't update in both places.

e.g.

<h2>Position 1</h2>
<ng-container [ngTemplateOutlet]="statusTemplate"></ng-container>
<h2>Position 2</h2>
<ng-container [ngTemplateOutlet]="statusTemplate"></ng-container>
<ng-template #statusTemplate>
  <h3 #status></h3>
</ng-template>

then i have this code dynically set the inner content of the view child, however the update doesnt appear in both places i re-use the template

@ViewChild('status', { static: false })
public status: any;

public setStatusTo(name: string): void {
  this.status.nativeElement.innerHTML = name;
}

The html looks like this when it runs in the browser

  <h2 _ngcontent-rdv-c3="">Position 1</h2>
  <!--bindings={
    "ng-reflect-ng-template-outlet": "[object Object]"
  }-->
  <h3 _ngcontent-rdv-c3="">Success</h3>
  <h2 _ngcontent-rdv-c3="">Position 2</h2>
  <!--bindings={
    "ng-reflect-ng-template-outlet": "[object Object]"
  }-->
  <h3 _ngcontent-rdv-c3=""></h3><!---->

enter image description here

How can i achieve updating the reused ng-template in multiple places? Why doesnt this work?


Solution

  • I would not do it this way (it seems easier to save the contents of h3 in a variable and then simply binding it) but if you want to take that approach, I would use ViewChildren instead of ViewChild

    import { Component, ViewChild, ViewChildren } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent {
      @ViewChildren('status')
      public statusElements: any;
    
      public setStatusTo(name: string): void {
        this.statusElements.toArray().forEach(
          (status) => {
            status.nativeElement.innerHTML = name;
          }
        ) 
      }
    }
    

    You can see the entire thing working here: https://stackblitz.com/edit/angular-af19ma