Добавление тегов скрипта в шаблон компонента Angular

Angular2 автоматически удаляет теги <script> из шаблонов, чтобы остановить людей, использующих эту функцию, в качестве "плохого человека" загрузчика.

Проблема здесь в том, что теги script в настоящее время имеют больше возможностей, чем просто загрузка кода или других файлов script. Существует вероятность того, что дальнейшая функциональность вокруг тегов <script> будет представлена ​​и в будущем.

Одним из текущих применений является JSON-LD, который принимает формат

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

Обычно предлагаемая работа заключается в динамическом добавлении тегов script в документ с помощью ngAfterViewInit hook, но это, очевидно, не является правильной практикой ng2 и будет не рабочая сторона сервера, которую, очевидно, должен иметь JSON-LD.

Существуют ли какие-либо другие обходные пути, которые мы можем использовать для включения тегов <script> в шаблоны angular2 (даже если тег инертен в браузере), или это случай, когда структура слишком самоуверенная? Какие другие решения могут существовать, если эта ситуация не может быть решена в angular2?

Ответы

Ответ 1

Может быть, немного поздно для вечеринки здесь, но так как вышеупомянутые ответы не работают хорошо с Angular SSR (например, document is not defined на стороне сервера или document.createElement is not a function), я решил написать версию, которая работает для Angular 4+, в контексте сервера и браузера:

Реализация компонентов

import { Renderer2, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

class MyComponent implements OnInit {

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

    public ngOnInit() {

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

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

Внедрение сервиса

ПРИМЕЧАНИЕ. Службы не могут использовать Renderer2 напрямую. Фактически, рендеринг элемента должен выполняться Компонентом. Однако вы можете оказаться в ситуации, когда вы хотите автоматизировать создание тегов JSON-LD script на странице. В качестве примера можно привести такую функцию для вызова событий изменения навигации по маршруту. Поэтому я решил добавить версию, которая работает в контексте Service.

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

/**
 * Use a Service to automate creation of JSON-LD Microdata.
 */
class MyService {

    constructor(
        @Inject(DOCUMENT) private _document: 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 script = renderer2.createElement('script');
        script.type = 'application/ld+json';
        script.text = '${JSON.stringify(data)}';

        renderer2.appendChild(this._document.body, script);
    }
}

Ответ 2

Нет способа Angular2 добавления тега script в шаблон.

Использование require(...) для загрузки внешних скриптов из класса компонентов упоминалось как обходное решение (не пробовал сам)

Для динамического добавления тега script используйте

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);
}

См. также angular2: в том числе скрипты сторонних js в компоненте

Ответ 3

Следующие работы с Angular 5.2.7:

Требуемый импорт:

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

Реализовать AfterViewInit:

export class HeroesComponent implements AfterViewInit {

Если ваш компонент реализует более одного интерфейса, разделите их запятой; например:

export class HeroesComponent implements OnInit, AfterViewInit {

Передайте следующие аргументы конструктору:

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

Добавьте метод ngAfterViewInit жизненного цикла представления:

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);
  }

Добавить afterScriptAdded функцию-член.

Эта функция будет вызвана после успешной загрузки внешнего скрипта. Таким образом, свойства или функции, которые вы хотите использовать из внешних js, будут доступны в теле этой функции.

 afterScriptAdded() {
    const params= {
      width: '350px',
      height: '420px',
    };
    if (typeof (window['functionFromExternalScript']) === 'function') {
      window['functionFromExternalScript'](params);
    }
  }

Ответ 4

На самом деле Нет способа Angular2 добавления тега script в шаблон. но вы можете сделать трюк в первую очередь, вы импортируете AfterViewInit и ElementRef из angular2 например:

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

, затем, вы будете реализовывать их в своем классе следующим образом:

export class example1 implements AfterViewInit{}

и вот очень простой трюк с использованием javascript, который вы собираетесь делать

 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

const head = document.getElementsByTagName('head')[0];
const _js = document.createElement('script');
_js.type = 'text/javascript';
_js.appendChild(document.createTextNode('{your js code here}'));
head.appendChild(_js);

это можно разместить где угодно, и это хороший подход