Добавление тегов скрипта в шаблон компонента 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?

 Günter Zöchbauer29 июн. 2016 г., 10:52
О проблеме сообщили вgithub.com/angular/angular/issues/9695

Ответы на вопрос(4)

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

 Günter Zöchbauer29 июн. 2016 г., 07:16
Я бы создал отчет об ошибке для этого варианта использования.
 Günter Zöchbauer29 июн. 2016 г., 06:15
Можете ли вы опубликовать ссылку на эту рекомендацию Google SEO?
 Günter Zöchbauer25 февр. 2017 г., 14:41
JSON-LD поддерживается некоторое время Angular, и он не будет удалять такие теги сценариев.
 Nicky21 апр. 2017 г., 17:11
@ GünterZöchbauer у тебя есть пример? Мои теги сценария по-прежнему удаляются4.0.2
 Ian Belcher29 июн. 2016 г., 07:20
Я добавил комментарий к оригинальной проблеме, где было решенополоса теги вместо того, чтобы делать ихинертный или иным образом. Приветствия для взгляда!
 Günter Zöchbauer21 апр. 2017 г., 17:19
Не могу себе представить, если вы используете мой код выше. Если вы используете другой код, я предлагаю вам создать новый вопрос и поделиться своим кодом.
 Ian Belcher29 июн. 2016 г., 06:13
Вы не можете использовать внешние сценарии с тегами сценариев JSON-LD в любом случае, так как сканеры не признают это. Скрипт должен содержать встроенные данные. Ты не виделлюбой способы вывода произвольных данных до Гюнтера? Реально это ограничение означает, что ни одно приложение angular2 не сможет делать структурированные данные для SEO так, как это рекомендует Google.

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

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
 }
}
Следующие работы с 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);
    }
  }
 Rafique Mohammed06 окт. 2018 г., 21:23
а как насчет ССР? Будет ли это работать?
Решение Вопроса

немного опоздал на вечеринку здесь, но так как приведенные выше ответы не очень хорошо работают с 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);
    }
}
 Nicky22 мая 2019 г., 16:16
Добро пожаловать, рад, что смог помочь :)
 David Votrubec07 сент. 2018 г., 13:30
Отлично, спасибо, что решили это. Мне нужна была только реализация на стороне клиента
 Maneesh Rao17 июн. 2019 г., 11:37
Я использую Angular 2 и получаю ошибку «Render2 не экспортируется». Мне нужно добавить схему в Angular 2 динамически в компоненте.
 Nicky19 июн. 2019 г., 12:02
@ManeeshRao Это правильно. Angular 2 не обеспечиваетRenderer2 еще. Вы можете увидеть это вархив документации Angular 2, Вы можете использовать имеющиесяRenderer в Angular 2 или обновите свою версию Angular, чтобы использоватьRenderer2, Надеюсь это поможет!
 BeetleJuice08 июл. 2017 г., 20:31
Пытаясь использоватьRendere2 в сервисе, как вы предложили, выдает ошибку:Нет провайдера для Renderer2". Увидетьэтот планк
 thrashead20 мар. 2019 г., 14:21
Спасибо чувак. Вы спасли мою жизнь :)
 Rafique Mohammed06 окт. 2018 г., 21:21
Потрясающие! Я искал это целую вечность. Угловая ССР дает много головной боли! я никогда не знаю, что renderer2 даже существует: D
 Nicky10 июл. 2017 г., 16:19
Renderer2 не может напрямую использоваться внутри службы. Вот почему в приведенном выше примере он отправляется в функциюsetJsonLd в качестве параметра, вместо зависимости самого сервиса. Чтобы это исправить, введитеRenderer2 сначала в вашем компоненте (НЕ в сервисе). Затем внедрите сервис в свой компонент. Наконец, вызовите сервисную функциюsetJsonLd сRenderer2 в качестве параметра (в приведенном выше примере это первый параметр). Надеюсь это поможет!

Ваш ответ на вопрос