0

I would like to access an element with ViewChild that is rendered with innerHtml, but in the lifecycle hook AfterViewInit, logging the element return undefined.

Below is the code used:

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

@Component({
  template: `<p [innerHTML]="'<ng-template #innerHtmlNgTemplate></ng-template>' | safeHtml"></p>`
})
export class AppComponent {
  @ViewChild('innerHtmlNgTemplate') public innerHtmlNgTemplate;

  ngAfterViewInit() {
      console.log(this.innerHtmlNgTemplate); // undefined
  }
}

The question is how can I access the <ng-template></ng-template> with ViewChild or in another way?

Cheers

EDIT:

Here is a stackblitz showing the issue. https://stackblitz.com/edit/angular-k1xeh6?file=src%2Fapp%2Fapp.component.ts

EDIT2:

In the stackblitz I sanitized the html, if this isn't done the ids are removed.

R. de Ruijter
  • 513
  • 5
  • 13

3 Answers3

0

Try Specifying the type for Viewchild (try below code)

  @ViewChild('innerHtmlNgTemplate') innerHtmlNgTemplate: ElementRef;
balajivaishnav
  • 2,795
  • 4
  • 23
  • 38
  • Thanks for your reply. I tried doing this, but the console log is still undefined. FYI: I added a stackblitz in the original post showing the issue – R. de Ruijter Mar 05 '20 at 12:05
0

Try this if you want to have reference to ng-template

import { Component, ViewChild, ChangeDetectorRef, AfterViewInit, ElementRef } from '@angular/core';

@Component({
  selector: 'app-component',
  template: `<p  
  [innerHTML]="'This is the innerhtml, and the following tag I want to select with ViewChild: '" >
     <ng-template #innerHtmlNgTemplate></ng-template>
  </p>

 `
})
export class AppComponent {
  @ViewChild('innerHtmlNgTemplate', {static: true}) public innerHtmlNgTemplate;

  ngAfterViewInit() {
      console.log(this.innerHtmlNgTemplate); // find value
  }
}

And use this if you want to reference innerHTML without changing the template

import { Component, ViewChild, ChangeDetectorRef, AfterViewInit, ElementRef } from '@angular/core';

@Component({
  selector: 'app-component',
  template: `<p  #innerHtmlNgTemplate
  [innerHTML]="'This is the innerhtml, and the following tag I want to select with ViewChild: <ng-template ></ng-template>'"></p>`
})
export class AppComponent {
  @ViewChild('innerHtmlNgTemplate', {static: true}) public innerHtmlNgTemplate;

  ngAfterViewInit() {
      console.log(this.innerHtmlNgTemplate.nativeElement.innerHTML); // prints innerhtml
  }
}
Gurpreet
  • 31
  • 1
  • 3
  • Thanks for your response. I think it would be good if I explain my goal. I get an HTML template from the backend. In this template, there will be a tag say ``. This tag I want to replace with an Angular component. My plan is to get the tag with ViewChild and replace the tag with the actual component. – R. de Ruijter Mar 05 '20 at 12:16
  • I have updated my answer. Let me know if you need something else – Gurpreet Mar 05 '20 at 12:20
  • https://stackoverflow.com/questions/36892632/angular2-replacing-component-dynamically-inside-another-component – Gurpreet Mar 05 '20 at 12:26
  • The big difference from what they do in the StackOverflow thread mentioned above is that the tag is *not* rendered inside of an innerHtml. – R. de Ruijter Mar 05 '20 at 12:30
0

The answer to the question is you should not do this. Angular is not designed to work this way.

This is the partial response from the angular issue thread.


When you insert HTML string through innerHTML, such string is not processed by Angular. As such you can't expect any Angular syntax / functionality (including queries) to work - simply put Angular has no chance of processing static HTML inserted into innerHTML. In this respect the observed behaviour "works as designed".

I'm not sure what your exact, functional use-case is but the scenario you've exposed is not something that Angular supports today and quite honestly, this is not how it was designed in the first place.

Github issue: https://github.com/angular/angular/issues/35874

R. de Ruijter
  • 513
  • 5
  • 13