Angular 2 how to execute script tag from innerHTML

匿名 (未验证) 提交于 2019-12-03 07:50:05

问题:

I have load the HTML page by http.get() method, and i add content this page to div tag.

getRequestToAssignPage (param: string) : any {      return this.$http.get(param)         .map((res: Response) => {              this.status = res;              return res.text();         })         .toPromise()         .then(response => {                let restr: string = response;                restr = restr.replace(/(<head[^>]*)(?:[^])*?\/head>/ig, '')                 .replace(/(<(\/?)body([^>]*?)>)/g, '')                 .replace(/(<style[^>]*)(?:[^])*?\/style>/g, '')                 .replace(/(<(\/?)html([^>]*?)>)/g, '')                 .replace(/(<app-root[^>]*)(?:[^])*?\/app-root>/ig, '')                 .replace(/(<\?[\s\S]*?\?>)|(<!DOCTYPE\s+\w+\s+\[[\s\S]*?\]>)|(<!\w[\s\S]*?>)/g, '')                 .replace(/(href\s*=\s*(?:"))/ig, 'href="/#')                 .replace(/(href\s*=\s*(?:'))/ig, "href='/#");                this.response = restr;           })         .catch(error => this.status = error );  } 

How you do you see, this method, put response in variable, and parse string by regular expressions Ok, and next I add it to div, like this

<div [innerHTML]="response | safe"></div> 

Good, my page is display. But, scripts doesn't work. They are exist in the div tag, but doesn't execute.

I had tried do that with eval() but this finished by poorly

let scripts: string[] = restr.match(/\<scr[\s\S]*?ipt>/g);              this.srcfield.nativeElement.innerHTML = '';              scripts.forEach((value, index) => {                 eval.call(null, (this.srcfield.nativeElement.innerHTML = value));             }); 

SyntaxError: Unexpected token <

Why innerHTML doesn't execute loaded script tags? How i can fix that?

回答1:

Based on the Adam's solution you can implement a custom directive along with the pipe and re-insert scripts into the DOM. This would account for both cases: inline scripts and "src" scripts. Keep in mind that allowing scripts like so is very dangerous.

Pipe:

import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser';  @Pipe({ name: 'safeHtml' }) export class SafeHtmlPipe implements PipeTransform {     constructor(private sanitizer: DomSanitizer) { }      transform(html) {         return this.sanitizer.bypassSecurityTrustHtml(html);     } } 

Directive:

import { Directive, ElementRef, OnInit } from '@angular/core';  @Directive({ selector: '[runScripts]' }) export class RunScriptsDirective implements OnInit {     constructor(private elementRef: ElementRef) { }     ngOnInit(): void {         setTimeout(() => { // wait for DOM rendering             this.reinsertScripts();         });     }     reinsertScripts(): void {         const scripts = <HTMLScriptElement[]>this.elementRef.nativeElement.getElementsByTagName('script');         const scriptsInitialLength = scripts.length;         for (let i = 0; i < scriptsInitialLength; i++) {             const script = scripts[i];             const scriptCopy = <HTMLScriptElement>document.createElement('script');             scriptCopy.type = script.type ? script.type : 'text/javascript';             if (script.innerHTML) {                 scriptCopy.innerHTML = script.innerHTML;             } else if (script.src) {                 scriptCopy.src = script.src;             }             scriptCopy.async = false;             script.parentNode.replaceChild(scriptCopy, script);         }     } } 

Usage:

<div [innerHTML]="myDynamicMarkup | safeHtml" runScripts></div> 


回答2:

In your template, you can set up something like:

<div #htmlContainer [innerHTML]="trustedHTML"></div> 

In the corresponding component, you can load your HTML into your template, build up an array of script tags, and eval each one:

@ViewChild('htmlContainer') container;  ngOnInit() {   this.http.get('html-file.html').subscribe((res: Response) => {     this.trustedHTML = this.sanitizer.bypassSecurityTrustHtml(res.text());      setTimeout(() => { //wait for DOM rendering       let scripts = this.container.nativeElement.getElementsByTagName('script');       for (let script of scripts){         eval(script.text)       }     })    }); 

I hate that I have to resort to using setTimeout and eval for something so seemingly simple, but it works.

...but not for <script src=".... I ended up importing jQuery and using $(parent).load(url);. If someone has a pure Angular solution, please post it.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!