iframe inside angular2 component, Property ‘contentWindow’ does not exist on type ‘HTMLElement’

I have an iframe inside a angular2 component, and I am trying to change the content of the iframe by accessing the contentWindow.
The iframe should contain a simple button.

My code:

    import { Component } from '@angular/core';
    @Component({
      moduleId: module.id,
      selector: 'component-iframe',
      template: '<iframe id="iframe"></iframe>'
    })
    export class ComponentIframe  {
      constructor() {
        let iframe = document.getElementById('iframe'); 
        let content="<button id="button" class="button" >My button </button>";
        let doc =  iframe.contentDocument || iframe.contentWindow;
        doc.open();
        doc.write(content);
      doc.close();
    }
   }

If I comment the constructor’s code and start the app, it compiles and runs correctly. Then I uncomment and all runs perfectly (the button is present in the iframe).

If I decomment the code then start the app (npm start) I have compilation bugs with the message:

Property ‘contentWindow’ does not exist on type ‘HTMLElement’

.

I also tried the alternative of putting the costructor’s code into ngOnInit(), ngAfterContentInit(), ngAfterViewInit() but the error persists.

The template doesn’t exist in the DOM yet when the constructor is executed

Use instead

import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
  moduleId: module.id,
  selector: 'component-iframe',
  template: '<iframe #iframe></iframe>'
})
export class ComponentIframe  {
  @ViewChild('iframe') iframe: ElementRef;

  ngAfterViewInit() {
    let content="<button id="button" class="button" >My button </button>";
    let doc =  this.iframe.nativeElement.contentDocument || this.iframe.nativeElement.contentWindow;
    doc.open();
    doc.write(content);
    doc.close();
  }
}

use this:

let iframe = document.getElementById('iframe') as HTMLIFrameElement

I solved the problem in the following way:

const element: HTMLIFrameElement = document.getElementById('iframe') as HTMLIFrameElement;
const iframe = element.contentWindow;
if (iframe !== null) {
  ...
}

If the content of the IFRAME is created by the same origin then I would suggest to use the IFRAME attribute srcDoc to set and change content in IFRAME.

@Component({
  selector: 'my-app',
  template: `
    <p><label for="text">Write content here...</label></p>
    <textarea 
        #text
        rows="10" 
        cols="47" 
        placeholder="Write some HTML content here..." 
        [(ngModel)]="srcDocContent"></textarea>

    <p>Preview HTML content in IFRAME</p>
    <iframe 
        sandbox="allow-same-origin" 
        [attr.srcDoc]="srcDocContent"></iframe>
  `
})
export class App {

  srcDocContent:string

  constructor() {
    this.srcDocContent="Some <strong>HTML</strong> content here..."
  }
}

See this PLUNKER DEMO

Read More:   How does Firefox reader view operate

or this Stackblitz DEMO

This will let the native HTML elements untouched to remain compatible with Angular Universal.

As Günter Zöchbauer has already answered it correctly. I would like to modify it a bit.

The DOM is not ready in Constructor yet but you can find it ready in ngOnInit event though by using { static: true } property something like this:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
@Component({
  moduleId: module.id,
  selector: 'component-iframe',
  template: '<iframe #iframe></iframe>'
})
export class ComponentIframe implements OnInit {
  @ViewChild('iframe', { static: true }) iframe: ElementRef;

  ngOnInit() {
    let content="<button id="button" class="button" >My button </button>";
    let doc =  this.iframe.nativeElement.contentDocument || this.iframe.nativeElement.contentWindow;
    doc.open();
    doc.write(content);
    doc.close();
  }
}

I solved the problem in the following way:

 var ID = document.getElementById("Iframe");
 var Iframe = eval("(ID.contentWindow || ID.contentDocument)");
 Iframe.CallIframeFunction();

Or use the now famous Typescript work around:

iframe['contentWindow']


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts