Need to insert Script tag in angular 2

I've already done a bit of reading and searching and pretty much everything I find points to that a script tag cannot be included in a template in Angular 2.

we are removing tags from templates on purpose as you shouldn't use those to load code on demand. https://github.com/angular/angular/issues/4903 [2015]

However - there is a function bypassSecurityTrustScript

I'd like to know when and how bypassSecurityTrustScript in Angular 2 is intended to be used?

I know a similar question has been asked: Angular2 dynamically insert script tag - though no one answered their question of how to use bypassSecurityTrustScript, and I'm not sure how the provided answer to that question could even work as it appears to use JavaScript within a template.


Having scripts in your views is usually a bad practice. If you insist on doing this you can use this component:

scripthack.component.html:

<div #script style.display="none">
  <ng-content></ng-content>
</div>

scripthack.component.ts:

import { Component, ElementRef, ViewChild, Input } from '@angular/core';

@Component({
    selector: 'script-hack',
    templateUrl: './scripthack.component.html'
})
export class ScriptHackComponent {

    @Input()
    src: string;

    @Input()
    type: string;

    @ViewChild('script') script: ElementRef;

    convertToScript() {
        var element = this.script.nativeElement;
        var script = document.createElement("script");
        script.type = this.type ? this.type : "text/javascript";
        if (this.src) {
            script.src = this.src;
        }
        if (element.innerHTML) {
            script.innerHTML = element.innerHTML;
        }
        var parent = element.parentElement;
        parent.parentElement.replaceChild(script, parent);
    }

    ngAfterViewInit() {
        this.convertToScript();
    }
}

usage (inline):

<script-hack>alert('hoi');</script-hack>

usage (external):

<script-hack src="//platform.twitter.com/widgets.js" type="text/javascript"></script-hack>

Turns out I was thinking about this a bit wrong. I was trying to find a way to put the script into the template by using standard Angular template variables. When Angular populates the template, it cleanses the values and so the script tags are lost.

I managed to finally get the script tags in following this article: https://netbasal.com/angular-2-security-the-domsanitizer-service-2202c83bd90#.7njysc6z1

That then left me with the problem described by: Angular2 dynamically insert script tag

I then moved the logic into the component class based on this: Where does DOM manipulation belong in Angular 2?


I had a similar use case, where I don't know if the HTML will contain a script tag. Since HTML5 doesn't execute the script if it's part of an innerHTML assignment, I used a slightly different approach.
This is part of a plugin system, so I needed to be able to add html+scripts on demand.

Source here - https://github.com/savantly-net/sprout-platform/blob/development/web/sprout-web-ui/src/app/dynamic/dynamic.component.ts

    import { Component, Input, AfterViewInit, ViewChild, Directive, ElementRef } from '@angular/core';
    
    @Directive({
      /* tslint:disable-next-line:directive-selector */
      selector: 'dynamic-directive'
    })
    export class DynamicDirective {}
    
    @Component({
      template: `<dynamic-directive></dynamic-directive>`
    })
    export class DynamicComponent implements AfterViewInit {
      @Input() body: any;
      @ViewChild(DynamicDirective, {read: ElementRef}) dynamic: ElementRef;
    
      constructor() { }
    
      // loads all the html from the plugin, but removes the script tags and appends them individually,
      // since html will not execute them if they are part of the innerHTML
      ngAfterViewInit(): void {
        const div = document.createElement('div');
        div.innerHTML = this.body;
        const scriptElements = [];
        const scriptNodes = div.querySelectorAll('script');
        for (let i = 0; i < scriptNodes.length; i++) {
          const scriptNode = scriptNodes[i];
          // Create a new script element so HTML5 will execute it upon adding to DOM
          const scriptElement = document.createElement('script');
          // Copy all the attributes from the original script element
          for (let aI = 0; aI < scriptNode.attributes.length; aI++) {
            scriptElement.attributes.setNamedItem(<Attr>scriptNode.attributes[aI].cloneNode());
          }
          // Add any content the original script element has
          const scriptContent = document.createTextNode(scriptNode.textContent);
          scriptElement.appendChild(scriptContent);
          // Remove the original script element
          scriptNode.remove();
          // add the new element to the list
          scriptElements.push(scriptElement);
        }
        this.dynamic.nativeElement.appendChild(div);
        // Finally add the new script elements to the DOM
        for (let i = 0; i < scriptElements.length; i++) {
          this.dynamic.nativeElement.appendChild(scriptElements[i]);
        }
      }
    }