Agregar etiquetas de script en la plantilla de componente Angular


Angular2 elimina las etiquetas <script> automáticamente de las plantillas para evitar que las personas usen esta funcionalidad como un cargador "poor's man" .

El problema aquí es que las etiquetas de script actualmente tienen más usos que solo cargar código u otros archivos de script. Existe la posibilidad de que en el futuro también se introduzcan más funcionalidades en torno a las etiquetas <script>.

Un uso actual es JSON-LD que toma el formato

<script type="application/ld+json">
{
    "@context":"http://schema.org",
    "@type":"HealthClub",
    ...
}
</script>

Una solución comúnmente sugerida es: agregue dinámicamente etiquetas de script al documento a través del gancho ngAfterViewInit, pero esto obviamente no es una práctica adecuada de ng2 y no funcionará en el lado del servidor, lo que JSON-LD obviamente debe poder hacer.

¿Hay alguna otra solución que podamos usar para incluir etiquetas <script> en plantillas angular2 (incluso si la etiqueta es inerte dentro del navegador) o es un caso de que el framework sea demasiado obstinado? ¿Qué otras soluciones podrían existir si esta situación no se puede resolver en angular2?

Author: Ian Belcher, 2016-06-29

4 answers

Tal vez un poco tarde para la fiesta aquí, pero como las respuestas anteriores no funcionan bien con Angular SSR (por ejemplo, document is not defined lado del servidor o document.createElement is not a function), decidí escribir una versión que funcione para Angular 4+, tanto en el servidor como en el contexto del navegador :

Component Implementation

import { Renderer2, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

class MyComponent implements OnInit {

    constructor(private _renderer2: Renderer2, @Inject(DOCUMENT) private _document) {

    }

    public ngOnInit() {

        let s = this._renderer2.createElement('script');
        s.type = `application/ld+json`;
        s.text = `
            {
                "@context": "https://schema.org"
                /* your schema.org microdata goes here */
            }
        `;

        this._renderer2.appendChild(this._document.body, s);
    }
}

Implementación de servicios

NOTA: Los servicios no pueden usar Renderer2 directamente. De hecho, el elemento de renderizado se supone que lo hace un Componente. Sin embargo, es posible que se encuentra en una situación en la que desea automatizar la creación de etiquetas JSON-LD script en una página. Una situación podría ser invocar dicha función en eventos de cambio de navegación de ruta. Por lo tanto, decidí agregar una versión que funcione en un contexto Service.

import { Renderer2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

class MyService {

    constructor(@Inject(DOCUMENT) private _document) {

    }

    /**
     * Set JSON-LD Microdata on the Document Body.
     *
     * @param renderer2             The Angular Renderer
     * @param data                  The data for the JSON-LD script
     * @returns void
     */
    public setJsonLd(renderer2: Renderer2, data: any): void {

        let s = renderer2.createElement('script');
        s.type = `application/ld+json`;
        s.text = `${JSON.stringify(data)}`;

        renderer2.appendChild(this._document.body, s);
    }
}
 18
Author: Nicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-22 13:13:10

No hay una forma Angular2 de agregar una etiqueta de script a una plantilla.

Usar require(...) para cargar scripts externos de la clase components se mencionó como una solución alternativa (no lo he probado yo mismo)

Para agregar dinámicamente una etiqueta de script use

constructor(private elementRef:ElementRef) {};

ngAfterViewInit() {
  var s = document.createElement("script");
  s.type = "text/javascript";
  s.src = "http://somedomain.com/somescript";
  this.elementRef.nativeElement.appendChild(s);
}

Ver también angular2: incluir scripts js de tercera parte en el componente

 14
Author: Günter Zöchbauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:03

Actualmente No existe una forma Angular2 de agregar una etiqueta de script a una plantilla. pero puedes hacer algún truco en primer lugar importarás AfterViewInit y ElementRef desde angular2 así:

import {Component,AfterViewInit,ElementRef} from 'Angular2/core';

Entonces los implementarás en tu clase así :{[16]]}

export class example1 implements AfterViewInit{}

Y aquí hay un truco dom javascript muy simple que vas a hacer

 export class example1 implements AfterViewInit{
 ngAfterViewInit()
 {
  var s=document.createElement("script");
  s.type="text/javascript";
  s.innerHTML="console.log('done');"; //inline script
  s.src="path/test.js"; //external script
 }
}
 5
Author: Mohsen M. Galal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-25 13:39:56

Lo siguiente funciona con Angular 5.2.7:

Las importaciones requeridas son:

import { Inject, AfterViewInit, ElementRef } from '@angular/core';
import { DOCUMENT } from '@angular/common';

Implementar AfterViewInit:

export class HeroesComponent implements AfterViewInit {

Si su componente está implementando más de una interfaz, sepárela por coma; por ejemplo:

export class HeroesComponent implements OnInit, AfterViewInit {

Pase los siguientes argumentos al constructor:

constructor(@Inject(DOCUMENT) private document, private elementRef: ElementRef) { }

Añadir ngAfterViewInit método de ver ciclo de vida:

ngAfterViewInit() {
    const s = this.document.createElement('script');
    s.type = 'text/javascript';
    s.src = '//external.script.com/script.js';
    const __this = this; //to store the current instance to call 
                         //afterScriptAdded function on onload event of 
                         //script.
    s.onload = function () { __this.afterScriptAdded(); };
    this.elementRef.nativeElement.appendChild(s);
  }

Agregue la función miembro afterScriptAdded.

Esta función se llamará después de que el script externo sea cargado con éxito. Por lo tanto, las propiedades o funciones que desea utilizar desde js externo se accederá en el cuerpo de esta función.

 afterScriptAdded() {
    const params= {
      width: '350px',
      height: '420px',
    };
    if (typeof (window['functionFromExternalScript']) === 'function') {
      window['functionFromExternalScript'](params);
    }
  }
 5
Author: Ketan Yekale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-06 05:59:33