8

I'm getting from server content into json object field, where it is html, <style></style> and <script></script> tags, and I want to execute it like this:

[innerHtml]="content | sanitize", but <script></script> tags do not execute. Is it possible to make it work?

My sanitize pipe looks like this:

import {Pipe} from '@angular/core';
import {DomSanitizationService} from '@angular/platform-browser';

@Pipe({
    name: 'sanitize',
    pure: true
})
export class Sanitize {
    constructor(private sanitizer: DomSanitizationService) {

    }

    transform(html: string) {

        return this.sanitizer.bypassSecurityTrustHtml(html);
    }
}

I know, that there is bypassSecurityTrustScript function in DomSanitizationService, but how can I use it in my case?

6
  • How does json object look like? what you want to convert ? Commented Sep 13, 2016 at 14:55
  • Is the html added to the DOM? Do you get error messages in the browser console? Commented Sep 13, 2016 at 14:58
  • content looks like this: "<div>some html</div> <script>some code</script>" Commented Sep 13, 2016 at 14:59
  • and <script></script> does not executes Commented Sep 13, 2016 at 15:01
  • Html is adding correctly to the dom Commented Sep 13, 2016 at 15:04

3 Answers 3

27

It's not an angular 2's problem, script tags inserted via innerHTML are not executed.

If you have html string that contains script tags insert it this way:

const fragment = document.createRange().createContextualFragment(yourHtmlString);
anyElement.appendChild(fragment);
Sign up to request clarification or add additional context in comments.

1 Comment

For others that may need to add a script to the body at some point, but intentionally don't want it bootstrapped on initial page load with the rest of the app: document.body.appendChild(fragment) could also work on the second line of Alex's code rather than setting up a ViewChild in Angular.
2

This will solve the issue...

import { Pipe } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
  name: 'sanitize',
  pure: true
})
export class Sanitize {

  constructor(private domSanitizer: DomSanitizer) { }


  handleExternalScriptsInHtmlString(string) {
    let that = this;
    var parser = new DOMParser();
    var scripts = parser.parseFromString(string, 'text/html').getElementsByTagName('script');
    var results = [];

    for (var i = 0; i < scripts.length; i++) {
      var src = scripts[i].getAttribute('src');
      if (src.length && results.indexOf(src) === -1) {
        results.push(src);
        that.addScript(src);
      }
    }

    return results;
  }

  addScript(src) {
    var script = document.createElement('script');
    script.setAttribute('src', src);
    document.body.appendChild(script);
  }


  transform(htmlContent: any) {
    let sanitizeHtmlContent = this.domSanitizer.bypassSecurityTrustHtml(htmlContent);

    this.handleExternalScriptsInHtmlString(htmlContent);

    return sanitizeHtmlContent;
  }
}

Comments

1

There is no angular way... You need to do it like this....

import { Pipe } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
  name: 'sanitize',
  pure: true
})
export class Sanitize {

  constructor(private domSanitizer: DomSanitizer) { }


  handleExternalScriptsInHtmlString(string) {
    let that = this;
    var parser = new DOMParser();
    var scripts = parser.parseFromString(string, 'text/html').getElementsByTagName('script');
    var results = [];

    for (var i = 0; i < scripts.length; i++) {
      var src = scripts[i].getAttribute('src');
      if (src.length && results.indexOf(src) === -1) {
        results.push(src);
        that.addScript(src);
      }
    }

    return results;
  }

  addScript(src) {
    var script = document.createElement('script');
    script.setAttribute('src', src);
    document.body.appendChild(script);
  }


  transform(htmlContent: any) {
    let sanitizeHtmlContent = this.domSanitizer.bypassSecurityTrustHtml(htmlContent);

    this.handleExternalScriptsInHtmlString(htmlContent);

    return sanitizeHtmlContent;
  }
}

3 Comments

this has the same issue, right? because you still just get a variable that you'd have to display using innerHtml which doesn't execute script tags
@SeanKPS No this one will execute the script tags in fact. Notice the function addScript. We are manually finding script tags and explicitly adding them to DOM
I thought angular wouldn't execute script tags at all -even if they're in the DOM. Maybe that's only within component templates and doesn't apply when appended to the body directly. Still, I needed to put the script output exactly where the script tag was in the DOM, for Github Gists, I ended up writing a couple functions to sort it out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.