web-dev-qa-db-fra.com

Ajout de balises de script dans Angular

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?

35
Ian Belcher

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

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

16
Günter Zöchbauer

Ce qui suit fonctionne avec Angular 5.2.7:

Les importations requises sont:

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

Implémentez AfterViewInit:

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 {

Passez les arguments ci-dessous au constructeur:

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

Ajoutez la méthode de cycle de vie de la vue 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);
  }

Ajouter une fonction membre afterScriptAdded.

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);
    }
  }
11
Ketan Yekale

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
 }
}
5
Mohsen M. Galal