5

I want to display the content of a templated webpage inside an iframe. But after loading the content the template doesn't get interpolated by angular. Is it because the change detection system? Could it be achieved some other way?

@Component({
  selector: 'my-app',
  template : `<iframe [src]="template" width="100%" height="300px"></iframe>`
})
export class App {
  template: string = `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <title>Page title</title>

      </head>
      <body>
        <p>{{strings[0]}}</p>
        <p>{{strings[1]}}</p>
        <p>{{strings[2]}}</p>
      </body>
    </html>
  `;
  strings: string[] = ['first element', 'second element', 'third element'];
  constructor(){
    this.template = 'data:text/html;charset=utf-8,' + encodeURI(this.template);
  }
}

bootstrap(App)

http://plnkr.co/edit/mWrqv1?p=preview

It doesn't seem to work either using innerHtml binding:

@Component({
  selector: 'my-app',
  template : `<div [innerHtml]="template"></div>`
})
export class App {
  template: string = `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <title>Page title</title>

      </head>
      <body>
        <p>{{strings[0]}}</p>
        <p>{{strings[1]}}</p>
        <p>{{strings[2]}}</p>
      </body>
    </html>
  `;
  strings: string[] = ['first element', 'second element', 'third element'];

}

bootstrap(App)

http://plnkr.co/edit/wscpSR?p=preview

dinigo
  • 6,872
  • 4
  • 37
  • 48

2 Answers2

8

you should use [srcdoc]

template: `<iframe id="{{patternId}}" [srcdoc]="srcdoc" > </iframe>`,

to pass the content you should use the DomSanitizationService to be able to pass script, form elemet.

constructor(private sanitizer: DomSanitizationService) {}

ngOnInit():any {
this.srcdoc = this.sanitizer.bypassSecurityTrustHtml(this.data.patternSource);
}

see https://angular.io/docs/ts/latest/guide/security.html#!#xss

javadev28hu
  • 160
  • 1
  • 5
1

[src]="template" and [innerHtml]="template" generally doesn't trigger any interpolation or component or directive instantiation. The behavior you describe is therefore expected and as designed.

Interplation is only triggered by HTML and bindings that are added to the template directly.

You can load a different Angular application inside the <iframe> and use postMessage to pass data between the main application and the <iframe>

If it is only for one-time interpolation, you can use TypeScripts string interpolation like

export class App {
  template: string = `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <title>Page title</title>

      </head>
      <body>
        <p>${strings[0]}</p>
        <p>${strings[1]}</p>
        <p>${strings[2]}</p>
      </body>
    </html>
  `;
  strings: string[] = ['first element', 'second element', 'third element'];
  constructor(){
    this.template = 'data:text/html;charset=utf-8,' + encodeURI(this.template);
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567