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?
Security considerations HTML specifies that a <script> tag inserted with innerHTML should not execute. For that reason, it is recommended that instead of innerHTML you use: Element.
Angular 14 provides a [innerHTML] property binding that you can use to render HTML instead of using interpolation, which will, as you might have noticed, render any HTML string as a plain text.
AngularJS is a JavaScript framework. It can be added to an HTML page with a <script> tag.
The <script> tag is used to embed a client-side script (JavaScript). The <script> element either contains scripting statements, or it points to an external script file through the src attribute. Common uses for JavaScript are image manipulation, form validation, and dynamic changes of content.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With