Добавление тегов скрипта в шаблон компонента 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);
это можно разместить где угодно, и это хороший подход