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

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

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

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

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

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

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

7 ответов

Решение

Может быть, немного опоздал на вечеринку здесь, но так как вышеупомянутые ответы не работают хорошо с 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/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);
    }
}

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

ПРИМЕЧАНИЕ. Службы не могут использовать Renderer2 непосредственно. Фактически, рендеринг элемента должен выполняться Компонентом. Однако вы можете оказаться в ситуации, когда вы хотите автоматизировать создание JSON-LD. script теги на странице. Ситуация может состоять в том, чтобы вызвать такую ​​функцию на событиях изменения навигации маршрута. Поэтому я решил добавить версию, которая работает в 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);
    }
}

В Angular2 нет способа добавить тег шаблона в шаблон.

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

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

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-скриптов в компонент

Следующее работает с 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);
    }
  }

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

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

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

export class example1 implements AfterViewInit{}

и вот очень простой трюк с Ja vaScript, который ты собираешься делать

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

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

Я добавил динамическую загрузку js-скрипта с условием внутри хука инициализации компонента следующим образом:

    private loadChatWithScript() {
    let chatScript = document.createElement("script");
    chatScript.type = "text/javascript";
    chatScript.async = true;
    chatScript.src = "https://chat-assets.frontapp.com/v1/chat.bundle.js";
    document.body.appendChild(chatScript);

    let chatScriptConfiguration = document.createElement("script");
    chatScriptConfiguration.type = "text/javascript";
    chatScriptConfiguration.async = true;
    chatScriptConfiguration.innerHTML = "window.FCSP = 'some-key-123'";
    document.body.appendChild(chatScriptConfiguration);
}

Джентльмен/джентльмен, пожалуйста, взгляните.

Для добавления пиксельных сценариев это может сэкономить ваше время. Это решение проще, чем любая разработка:

- Работает только на первой загруженной странице -

Находить внутри вашего проекта Angular настройте его примерно так (поместите свой скрипт в тег script):

      <!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My Angular Application</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
<script>
  // Put your script here
  alert('Test me, Angular hero!');
</script>
</body>
</html>

Для использования скрипта внутри шаблона углового компонента я предлагаю ответ @Nicky.

Другие вопросы по тегам