54 votes

Charger dynamiquement un fichier javascript externe à partir d'un composant angulaire

Je suis entrain de créer un Angulaire de l'application à l'aide Angulaire 4 et de la CLI. Je suis en train d'ajouter la SkyScanner widget de recherche dans un de mes composants.

Skyscanner Exemple Widget

Le cadre de la mise en œuvre nécessite l'ajout d'un nouveau script externe:

<script src="https://widgets.skyscanner.net/widget-server/js/loader.js" async></script>

Je ne suis pas sûr de la façon correcte de faire référence à ce fichier. Si j'ajoute le script dans mon index.html fichier, le widget n'a pas de charge, à moins qu'une actualisation de la page entière est effectuée. Je suppose que le script tente de manipuler le DOM de la charge et les éléments n'existent pas lorsque le script s'exécute.

Quelle est la bonne façon de charger le script uniquement lorsque le composant contenant la Skyscanner widget est chargé?

93voto

Sandip Patel Points 9692

Essayez de charger du JavaScript externe sur la charge des composants comme ci-dessous:

 loadAPI: Promise<any>;

constructor() {        
    this.loadAPI = new Promise((resolve) => {
        this.loadScript();
        resolve(true);
    });
}

public loadScript() {        
    var isFound = false;
    var scripts = document.getElementsByTagName("script")
    for (var i = 0; i < scripts.length; ++i) {
        if (scripts[i].getAttribute('src') != null && scripts[i].getAttribute('src').includes("loader")) {
            isFound = true;
        }
    }

    if (!isFound) {
        var dynamicScripts = ["https://widgets.skyscanner.net/widget-server/js/loader.js"];

        for (var i = 0; i < dynamicScripts .length; i++) {
            let node = document.createElement('script');
            node.src = dynamicScripts [i];
            node.type = 'text/javascript';
            node.async = false;
            node.charset = 'utf-8';
            document.getElementsByTagName('head')[0].appendChild(node);
        }

    }
}
 

47voto

William Cuervo Points 240

J'ai eu le même problème, mais dans mon cas, j'étais à l'importation de 10 bibliothèques à la fin du fichier html, et ces bibliothèques ont un grand nombre de méthodes, des auditeurs, des événements, et plus encore, et dans mon cas, je n'ai pas besoin d'appeler une méthode en particulier.

L'exemple sur ce que j'avais:

<!-- app.component.html -->

<div> 
 ...
</div>

<script src="http://www.some-library.com/library.js">
<script src="../assets/js/my-library.js"> <!-- a route in my angular project -->

Comme mentionné, il ne fonctionne pas. Ensuite, j'ai trouver un support qui m'a aidé: Milad réponse

  1. Supprimer les appels de script dans le app.component.html. Vous devez le lien de ces scripts dans l'application.composante.fichier ts.

  2. Dans ngOnInit(), utilisez une méthode pour ajouter les bibliothèques, par exemple:

`

<!-- app.component.ts -->

export class AppComponent implements OnInit {
   title = 'app';
   ngOnInit() {
     this.loadScript('http://www.some-library.com/library.js');
     this.loadScript('../assets/js/my-library.js');
   }
  }

  public loadScript(url: string) {
    const body = <HTMLDivElement> document.body;
    const script = document.createElement('script');
    script.innerHTML = '';
    script.src = url;
    script.async = false;
    script.defer = true;
    body.appendChild(script);
  }
}

Il fonctionne pour moi. J'utilise Angulaire 6, j'espère que ça aide.

8voto

Eduardo Vargas Points 2376

J'ai fait cet extrait de code

  addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.elementRef.nativeElement.appendChild(script);
    return script;
  }
 

Et puis appelez ça comme ça

 this.addJsToElement('https://widgets.skyscanner.net/widget-server/js/loader.js').onload = () => {
        console.log('SkyScanner Tag loaded');
}
 

EDIT: Avec le nouveau rendu Api, il peut être écrit comme ceci

 constructor(private renderer: Renderer2){}

 addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.renderer.appendChild(document.body, script);
    return script;
  }
 

StackBlitz

7voto

Hamed Baatour Points 3318

ajoutez loader.js à votre dossier d'actifs puis dans votre angular-cli.json

 "scripts": ["./src/assets/loader.js",]
 

puis ajoutez ceci à votre typings.d.ts

  declare var skyscanner:any;
 

et vous pourrez l'utiliser

   skyscanner.load("snippets","2");
 

7voto

Anil Agrawal Points 1076

Vous pouvez créer votre propre directive pour charger le script comme ci-dessous

 import { Directive, OnInit, Input } from '@angular/core';

@Directive({
    selector: '[appLoadScript]'
})
export class LoadScriptDirective implements OnInit{

    @Input('script') param:  any;

    ngOnInit() {
        let node = document.createElement('script');
        node.src = this.param;
        node.type = 'text/javascript';
        node.async = false;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }

}
 

Et vous pouvez l'utiliser n'importe où dans votre modèle de composants comme ci-dessous

 <i appLoadScript  [script]="'script_file_path'"></i>
 

Par exemple, pour charger dynamiquement JQuery dans votre composant, insérez le code ci-dessous dans le modèle de votre composant

 <i appLoadScript  [script]="'/assets/baker/js/jquery.min.js'"></i>
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X