Je crée une application angulaire utilisant Angular 4 et le CLI. J'essaie d'ajouter le widget de recherche SkyScanner à l'un de mes composants.
Une partie de l'implémentation 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 manière correcte de référencer ce fichier. Si j'ajoute le script dans mon fichier index.html, le widget ne se charge que si une actualisation complète de la page est effectuée. Je suppose que le script tente de manipuler le DOM lors du chargement et que les éléments n'existent pas lors de l'exécution du script.
Quelle est la bonne façon de charger le script uniquement lorsque le composant contenant le widget Skyscanner est chargé?
Essayez de charger du code JavaScript externe lors du chargement des composants, comme indiqué 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);
}
}
}
J'ai eu le même problème, mais dans mon cas, j'importais 10 bibliothèques à la fin du fichier html, et ces bibliothèques ont beaucoup de méthodes, d'écouteurs, d'événements et plus, et dans mon cas, je n'avais pas besoin appeler une méthode spécifiquement.
L'exemple de ce que j'ai eu:
<!-- 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é, cela n'a pas fonctionné. Ensuite, je trouve quelque chose qui m'a aidé: Réponse de Milad
Supprimez les appels de script dans le fichier app.component.html. Vous devez lier ces scripts dans le fichier app.component.ts.
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);
}
}
Cela fonctionne pour moi. J'utilise Angular 6, j'espère que ça aide.
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 comme ça
this.addJsToElement('https://widgets.skyscanner.net/widget-server/js/loader.js').onload = () => {
console.log('SkyScanner Tag loaded');
}
EDIT: Avec le nouveau moteur de 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;
}
ajoutez loader.js
à votre dossier de ressources, 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");
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 indiqué 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>
Remarque: Ceci est spécialement destiné aux liens js externes! Étape 1. Il est recommandé d'ajouter votre script angulaire au fichier index.html situé au bas de votre corps! J'ai essayé tous les autres moyens mais j'ai échoué.
<!-- File Name: index.html and its inside src dir-->
<body class="">
<app-root></app-root>
<!-- Icons -->
<script src="https://unpkg.com/feather-icons/dist/feather.min.js"></script>
</body>
Ensuite, il y a deux façons de faire cela ... Dans Anguar5, utilisez dans le dossier de votre composant en haut, tapez dans ce code
declare var feather:any;
dans votre classe, appelez la méthode dont vous avez besoin. Par exemple
//FileName: dashboard.component.ts
import { Component, OnInit } from '@angular/core';
declare var feather:any;
export class DashboardComponent implements OnInit{
ngOnInit(){
feather.replace();
}
}
et cela devrait exécuter votre code! L’autre façon qui pourrait fonctionner dans une version plus ancienne. Je n'ai pas vérifié!
//FileName: dashboard.component.ts
import { Component, OnInit } from '@angular/core';
export class DashboardComponent implements OnInit{
ngOnInit(){
let node = document.createElement('script');
node.innerText='feather.replace()';
node.type = 'text/javascript';
node.async = false;
node.charset = 'utf-8';
document.getElementsByTagName('body')[0].appendChild(node);
}
}
Si vous n'obtenez pas mon code, essayez également ceci link .
J'espère que cela t'aides!
Tu peux faire une chose
si vous avez angular-cli.json
alors vous pouvez déclarer au script
comme
"scripts": ["../src/assets/js/loader.js"]
Et puis déclarez skyscanner dans votre composant
comme
declare var skyscanner:any;
C'est tout!
J'espère que cela vous aidera
Un peu tard mais je préfère faire de cette façon (service moyen) ....
import { Injectable } from '@angular/core';
import { Observable } from "rxjs";
interface Scripts {
name: string;
src: string;
}
export const ScriptStore: Scripts[] = [
{ name: 'script-a', src: 'assets/js/a.js' },
{ name: 'script-b', src: 'assets/js/b.js' },
{ name: 'script-c', src: 'assets/js/c.js' }
];
declare var document: any;
@Injectable()
export class FileInjectorService {
private scripts: any = {};
constructor() {
ScriptStore.forEach((script: any) => {
this.scripts[script.name] = {
loaded: false,
src: script.src
};
});
}
loadJS(...scripts: string[]) {
const promises: any[] = [];
scripts.forEach((script) => promises.Push(this.loadJSFile(script)));
return Promise.all(promises);
}
loadJSFile(name: string) {
return new Promise((resolve, reject) => {
if (!this.scripts[name].loaded) {
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = this.scripts[name].src;
if (script.readyState) {
script.onreadystatechange = () => {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
}
};
} else {
script.onload = () => {
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
};
}
script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});
document.getElementsByTagName('head')[0].appendChild(script);
} else {
resolve({ script: name, loaded: true, status: 'Already Loaded' });
}
});
}
}
Ensuite, dans ma composante, je pourrais faire quelque chose comme:
ngOnInit() {
this.fileInjectorService.loadJS('script-a', 'script-c').then(data => {
// Loaded A and C....
}).catch(error => console.log(error));
}
Testé en angulaire 6/7