Angular2 supprime <script>
balises automatiquement à partir de modèles pour empêcher les utilisateurs d’utiliser cette fonctionnalité en tant que chargeur "pauvre" .
Le problème ici est que les balises de script ont actuellement plus d'utilisations que le simple chargement de code ou d'autres fichiers de script. Il est possible que d'autres fonctionnalités autour de <script>
Les balises seront également introduites à l’avenir.
Une utilisation courante est JSON-LD qui prend le format
<script type="application/ld+json">
{
"@context":"http://schema.org",
"@type":"HealthClub",
...
}
</script>
Une solution couramment suggérée consiste à ajouter dynamiquement des balises de script au document via le hook ngAfterViewInit
, mais ceci n’est évidemment pas une bonne pratique de ng2 et ne fonctionnera pas côté serveur, JSON-LD doit évidemment pouvoir le faire.
Existe-t-il d'autres solutions de contournement que nous pouvons utiliser pour inclure <script>
tags dans les templates angular2 (même si le tag est inerte dans le navigateur) ou s'agit-il d'un cas où le framework est trop avisé? Quelles autres solutions pourraient exister si cette situation ne pouvait pas être résolue dans angular2?
Peut-être un peu tard pour le parti ici, mais puisque les réponses ci-dessus ne fonctionnent pas bien avec Angular SSR (par exemple, document is not defined
côté serveur ou document.createElement is not a function
), J'ai décidé d'écrire une version qui fonctionne pour Angular 4+, dans le contexte du serveur et du navigateur:
implémentation de composant
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);
}
}
mise en œuvre du service
REMARQUE: les services ne peuvent pas utiliser Renderer2
directement. En fait, le rendu d'un élément est supposé être effectué par un composant. Cependant, vous pouvez vous retrouver dans une situation où vous souhaitez automatiser la création de balises JSON-LD script
sur une page. À titre d'exemple, une situation pourrait être d'invoquer une telle fonction lors d'événements de changement de navigation d'itinéraire. J'ai donc décidé d'ajouter une version qui fonctionne dans un contexte 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);
}
}
Il n’existe pas de méthode Angular2 pour ajouter une balise de script à un modèle.
Utiliser require(...)
pour charger des scripts externes à partir de la classe de composants a été mentionné comme solution de contournement (je ne l'ai pas essayé moi-même)
Pour ajouter dynamiquement une balise de script, utilisez
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);
}
Voir aussi angular2: incluant les scripts thirdparty js dans le composant
import { Inject, AfterViewInit, ElementRef } from '@angular/core';
import { DOCUMENT } from '@angular/common';
export class HeroesComponent implements AfterViewInit {
Si votre composant implémente plusieurs interfaces, séparez-les par une virgule. par exemple:
export class HeroesComponent implements OnInit, AfterViewInit {
constructor(@Inject(DOCUMENT) private document, private elementRef: ElementRef) { }
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);
}
Cette fonction sera appelée une fois le script externe chargé. Ainsi, les propriétés ou fonctions que vous souhaitez utiliser à partir de js externes seront accessibles dans le corps de cette fonction.
afterScriptAdded() {
const params= {
width: '350px',
height: '420px',
};
if (typeof (window['functionFromExternalScript']) === 'function') {
window['functionFromExternalScript'](params);
}
}
En fait Il n'y a pas de Angular2 moyen d'ajouter un balise de script à un modèle. mais vous pouvez faire quelques astucestout d'abord vous importerez AfterViewInit
et ElementRef
d'angular2 comme ceci:
import {Component,AfterViewInit,ElementRef} from 'Angular2/core';
alors vous allez les implémenter dans votre classe comme ça:
export class example1 implements AfterViewInit{}
et voici un truc très simple dom dom javascript tu vas faire
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
}
}