Wie lade ich externe Skripte dynamisch in Angular?

150

Ich habe dieses Modul, das die externe Bibliothek zusammen mit zusätzlicher Logik <script>komponiert, ohne das Tag direkt in die index.html einzufügen:

import 'http://external.com/path/file.js'
//import '../js/file.js'

@Component({
    selector: 'my-app',
    template: `
        <script src="http://iknow.com/this/does/not/work/either/file.js"></script>
        <div>Template</div>`
})
export class MyAppComponent {...}

Ich stelle fest, dass die importvon ES6-Spezifikation statisch ist und während des TypeScript-Transpilierens und nicht zur Laufzeit aufgelöst wird.

Wie auch immer, um es konfigurierbar zu machen, damit die Datei file.js entweder aus dem CDN oder aus dem lokalen Ordner geladen wird? Wie kann man Angular 2 anweisen, ein Skript dynamisch zu laden?

CallMeLaNN
quelle
Mögliches Duplikat des Importnamens
Felix Kling

Antworten:

61

Wenn Sie system.js verwenden, können Sie System.import()zur Laufzeit Folgendes verwenden :

export class MyAppComponent {
  constructor(){
    System.import('path/to/your/module').then(refToLoadedModule => {
      refToLoadedModule.someFunction();
    }
  );
}

Wenn Sie Webpack verwenden, können Sie die robuste Unterstützung der Codeaufteilung voll ausnutzen mit require.ensure:

export class MyAppComponent {
  constructor() {
     require.ensure(['path/to/your/module'], require => {
        let yourModule = require('path/to/your/module');
        yourModule.someFunction();
     }); 
  }
}
zog mehr
quelle
1
Es scheint, als müsste ich den Modullader speziell in der Komponente verwenden. Nun, das ist in Ordnung, da Systemdie Zukunft des Laders ist, denke ich.
CallMeLaNN
6
TypeScript Plugin for Sublime Textist mit Systemdem TypeScript-Code nicht zufrieden : Cannot find name 'System'aber kein Fehler beim Transpilieren und Ausführen. Beide Angular2und die SystemSkriptdatei wurden bereits hinzugefügt index.html. Wie dem auch sei , um importdas Systemund das Plugin glücklich zu machen?
CallMeLaNN
1
aber was ist, wenn Sie nicht system.js verwenden!
Murhaf Sousli
2
@rewmoore Ich erinnere mich nicht, warum ich das gesagt habe, require()/ importsollte jetzt als Ihre Antwort
gut funktionieren
9
Soweit ich weiß, funktionieren diese Optionen nicht für Skripte im Internet, sondern nur für lokale Dateien. Dies scheint die ursprüngliche Frage nicht zu beantworten.
WillyC
139

Mit der folgenden Technik können Sie JS-Skripte und -Bibliotheken bei Bedarf dynamisch in Ihr Angular-Projekt laden.

script.store.ts enthält den Pfad des Skripts entweder lokal oder auf einem Remote-Server und einen Namen , der zum dynamischen Laden des Skripts verwendet wird

 interface Scripts {
    name: string;
    src: string;
}  
export const ScriptStore: Scripts[] = [
    {name: 'filepicker', src: 'https://api.filestackapi.com/filestack.js'},
    {name: 'rangeSlider', src: '../../../assets/js/ion.rangeSlider.min.js'}
];

script.service.ts ist ein injizierbarer Dienst, der das Laden des Skripts übernimmt und so kopiert, script.service.tswie es ist

import {Injectable} from "@angular/core";
import {ScriptStore} from "./script.store";

declare var document: any;

@Injectable()
export class ScriptService {

private scripts: any = {};

constructor() {
    ScriptStore.forEach((script: any) => {
        this.scripts[script.name] = {
            loaded: false,
            src: script.src
        };
    });
}

load(...scripts: string[]) {
    var promises: any[] = [];
    scripts.forEach((script) => promises.push(this.loadScript(script)));
    return Promise.all(promises);
}

loadScript(name: string) {
    return new Promise((resolve, reject) => {
        //resolve if already loaded
        if (this.scripts[name].loaded) {
            resolve({script: name, loaded: true, status: 'Already Loaded'});
        }
        else {
            //load script
            let script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = this.scripts[name].src;
            if (script.readyState) {  //IE
                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 {  //Others
                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);
        }
    });
}

}

Injizieren Sie dies, ScriptServicewo immer Sie es brauchen, und laden Sie js libs wie folgt

this.script.load('filepicker', 'rangeSlider').then(data => {
    console.log('script loaded ', data);
}).catch(error => console.log(error));
Rahul Kumar
quelle
7
Das funktioniert hervorragend. Rasiert mehr als 1 MB von der anfänglichen Ladegröße - ich habe viele Bibliotheken!
Our_Benefactors
2
Sieht so aus, als hätte ich zu früh gesprochen. Diese Lösung funktioniert NICHT in iOS Safari.
Our_Benefactors
Überprüfen Sie nach dem Laden des Skripts, ob es an den Leiter Ihres Dom angehängt ist
Rahul Kumar
Vielleicht this.script.load is not a function
spritze
Vielen Dank. Dies funktioniert, aber ich lade mein Skript (eine Hintergrundanimation) in jede andere Komponente. Ich möchte, dass es nur auf meiner ersten Komponente geladen wird (es ist eine Anmeldeseite). Was kann ich tun, um das zu erreichen? Vielen Dank
Joel Azevedo
47

Das könnte funktionieren. Dieser Code hängt das <script>Tag dynamisch an die headangeklickte Schaltfläche der HTML-Datei an.

const url = 'http://iknow.com/this/does/not/work/either/file.js';

export class MyAppComponent {
    loadAPI: Promise<any>;

    public buttonClicked() {
        this.loadAPI = new Promise((resolve) => {
            console.log('resolving promise...');
            this.loadScript();
        });
    }

    public loadScript() {
        console.log('preparing to load...')
        let node = document.createElement('script');
        node.src = url;
        node.type = 'text/javascript';
        node.async = true;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }
}
ng-darren
quelle
1
Danke Mann hat für mich gearbeitet. Sie können es jetzt beim Laden der Seite auch mit der ngonit-Methode laden. Ein Klick auf die Schaltfläche ist also nicht erforderlich.
Niraj
Ich benutze den gleichen Weg .. aber nicht für mich gearbeitet. Kannst du mir bitte gleich helfen? this.loadJs ("Javascript-Dateipfad"); public loadjs (file) {let node = document.createElement ('script'); node.src = Datei; node.type = 'text / javascript'; node.async = true; node.charset = 'utf-8'; document.getElementsByTagName ('head') [0] .appendChild (node); }
Mitesh Shah
Versuchen Sie dies beim Klicken oder beim Laden der Seite? Können Sie uns mehr über das Ergebnis oder den Fehler erzählen?
Ng-Darren
Hallo, ich habe versucht, dies zu implementieren und funktioniert gut, new Promiseist aber nicht gelöst. Können Sie mir sagen, Promiseob ich etwas importieren muss?
user3145373 ツ
Hallo, ich habe nichts Besonderes importiert, als ich Promise verwendet habe.
Ng-Darren
23

Ich habe die Antwort von @rahul kumars so geändert, dass stattdessen Observables verwendet werden:

import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";

@Injectable()
export class ScriptLoaderService {
    private scripts: ScriptModel[] = [];

    public load(script: ScriptModel): Observable<ScriptModel> {
        return new Observable<ScriptModel>((observer: Observer<ScriptModel>) => {
            var existingScript = this.scripts.find(s => s.name == script.name);

            // Complete if already loaded
            if (existingScript && existingScript.loaded) {
                observer.next(existingScript);
                observer.complete();
            }
            else {
                // Add the script
                this.scripts = [...this.scripts, script];

                // Load the script
                let scriptElement = document.createElement("script");
                scriptElement.type = "text/javascript";
                scriptElement.src = script.src;

                scriptElement.onload = () => {
                    script.loaded = true;
                    observer.next(script);
                    observer.complete();
                };

                scriptElement.onerror = (error: any) => {
                    observer.error("Couldn't load script " + script.src);
                };

                document.getElementsByTagName('body')[0].appendChild(scriptElement);
            }
        });
    }
}

export interface ScriptModel {
    name: string,
    src: string,
    loaded: boolean
}
Joel
quelle
1
Sie vergessen, das asyncauf einzustellen true.
Will Huang
Ich habe eine Frage: Wenn wir das Skript anhängen und zwischen Routen navigieren, sagen wir, ich habe das Skript zu Hause geladen und zu about navigiert und bin nach Hause zurückgekehrt. Gibt es eine Möglichkeit, das aktuelle Skript neu zu starten? Bedeutet das, dass ich zuvor geladene entfernen und erneut laden möchte? Vielen Dank
d123546
@ d123546 Ja, wenn Sie möchten, dass es möglich ist. Sie müssten jedoch eine Logik schreiben, die das Skript-Tag entfernt. Schauen Sie hier: stackoverflow.com/questions/14708189/…
Joel
Danke Joel, aber gibt es eine Möglichkeit, die vom Skript initialisierten Funktionen irgendwie zu entfernen? Momentan habe ich ein Problem in meinem angle4-Projekt, weil ich ein Skript lade, das den jquery-Schieberegler initialisiert. Wenn also die erste Route geladen wird, wird sie ordnungsgemäß angezeigt. Wenn ich dann zu einer anderen Route navigiere und zu meiner Route zurückkehre, wird das Skript zweimal geladen und der Schieberegler wird nicht mehr
geladen
1
Es liegt ein Fehler in der Zeile vor private scripts: {ScriptModel}[] = [];. Es sollte seinprivate scripts: ScriptModel[] = [];
Chris Haines
20

Eine weitere Option wäre die Verwendung eines scriptjsPakets für diese Angelegenheit

Mit dieser Option können Sie Skriptressourcen bei Bedarf von einer beliebigen URL laden

Beispiel

Installieren Sie das Paket:

npm i scriptjs

und Typdefinitionen fürscriptjs :

npm install --save @types/scriptjs

Dann Importmethode $script.get():

import { get } from 'scriptjs';

und schließlich die Skriptressource laden, in unserem Fall die Google Maps-Bibliothek:

export class AppComponent implements OnInit {
  ngOnInit() {
    get("https://maps.googleapis.com/maps/api/js?key=", () => {
        //Google Maps library has been loaded...
    });
  }
}

Demo

Vadim Gremyachev
quelle
Vielen Dank für das Teilen, aber wie kann zusätzliche Eigenschaft mit URL wie Async Defer hinzufügen? Können Sie mir zeigen, wie ich dieses Skript mithilfe der obigen Bibliothek lade? <script type = 'text / javascript' src = ' bing.com/api/maps/mapcontrol?branch=release ' async defer> </ script>
Pushkar Rathod
Da die Betreffzeile dieselbe ist, hüpfe ich nur hier
Pushkar Rathod
Großartig, aber anstelle von npm install --save @ types / scriptjs sollte es npm install sein --save-dev @ types / scriptjs (oder nur npm i -D @ types / scriptjs)
Youness Houdass
18

Sie können mehrere Skripte dynamisch wie folgt in Ihre component.tsDatei laden :

 loadScripts() {
    const dynamicScripts = [
     'https://platform.twitter.com/widgets.js',
     '../../../assets/js/dummyjs.min.js'
    ];
    for (let i = 0; i < dynamicScripts.length; i++) {
      const 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);
    }
  }

und rufen Sie diese Methode im Konstruktor auf,

constructor() {
    this.loadScripts();
}

Hinweis: Wenn weitere Skripts dynamisch geladen werden sollen, fügen Sie sie dem dynamicScriptsArray hinzu.

Aswin Sanakan
quelle
3
Ich muss sagen, das sieht einfach aus, funktioniert aber gut und ist sehr einfach zu implementieren :-)
Pierre
3
Das Problem bei dieser Art der Skriptinjektion besteht darin, dass dieses Skript, da Angular ein SPA ist, im Grunde genommen im Browser-Cache verbleibt, selbst nachdem Sie das Skript-Tag aus dem DOM entfernt haben.
J4rey
1
Super Antwort! Hat meinen Tag gerettet, es funktioniert mit Angular 6 & 7. Getestet!
Nadeeshan Herath
Um Daten an externe js zu senden und Daten von externen js abzurufen, rufen Sie diese Funktion unter app.component.ts auf und deklarieren Sie var d3Sankey: any auf einer beliebigen Komponente eines Moduls auf Funktionsebene. Es funktioniert.
Gnganpath
5

Ich habe dieses Code-Snippet mit der neuen Renderer-API erstellt

 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;
  }

Und dann nenne es so

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

StackBlitz

Eduardo Vargas
quelle
4

Ich habe eine gute Möglichkeit, Skripte dynamisch zu laden! Jetzt verwende ich in meinem Projekt ng6, echarts4 (> 700 KB), ngx-echarts3. Wenn ich sie in den Dokumenten von ngx-echarts verwende, muss ich Echarts in angle.json importieren: "scripts": ["./ node_modules / echarts / dist / echarts.min.js"], also im Anmeldemodul, Seite beim Laden von Skripten .js, das ist eine große Datei! Ich will es nicht

Ich denke also, jedes Modul wird als Datei per Winkel geladen. Ich kann einen Router-Resolver einfügen, um js vorzuladen, und dann mit dem Laden des Moduls beginnen!

// PreloadScriptResolver.service.js

/**动态加载js的服务 */
@Injectable({
  providedIn: 'root'
})
export class PreloadScriptResolver implements Resolve<IPreloadScriptResult[]> {
  // Here import all dynamically js file
  private scripts: any = {
    echarts: { loaded: false, src: "assets/lib/echarts.min.js" }
  };
  constructor() { }
  load(...scripts: string[]) {
    const promises = scripts.map(script => this.loadScript(script));
    return Promise.all(promises);
  }
  loadScript(name: string): Promise<IPreloadScriptResult> {
    return new Promise((resolve, reject) => {
      if (this.scripts[name].loaded) {
        resolve({ script: name, loaded: true, status: 'Already Loaded' });
      } else {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = this.scripts[name].src;
        script.onload = () => {
          this.scripts[name].loaded = true;
          resolve({ script: name, loaded: true, status: 'Loaded' });
        };
        script.onerror = (error: any) => reject({ script: name, loaded: false, status: 'Loaded Error:' + error.toString() });
        document.head.appendChild(script);
      }
    });
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<IPreloadScriptResult[]> {
   return this.load(...route.routeConfig.data.preloadScripts);
  }
}

Importieren Sie dann in submodule-routing.module.ts Pr diesen PreloadScriptResolver:

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    canActivate: [AuthGuardService],
    canActivateChild: [AuthGuardService],
    resolve: {
      preloadScripts: PreloadScriptResolver
    },
    data: {
      preloadScripts: ["echarts"]  // important!
    },
    children: [.....]
}

Dieser Code funktioniert gut und verspricht Folgendes: Nachdem die js-Datei geladen wurde, beginnt das Laden des Moduls! Dieser Resolver kann in vielen Routern verwendet werden

申君健
quelle
Könnten Sie bitte den Code der IPreloadScriptResult-Schnittstelle teilen?
Mehul Bhalala
3

Eine universelle Winkellösung; Ich musste warten, bis ein bestimmtes Element auf der Seite war, bevor ich ein Skript zum Abspielen eines Videos lud.

import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
import {isPlatformBrowser} from "@angular/common";

@Injectable({
  providedIn: 'root'
})
export class ScriptLoaderService {

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
  ) {
  }

  load(scriptUrl: string) {
    if (isPlatformBrowser(this.platformId)) {
      let node: any = document.createElement('script');
      node.src = scriptUrl;
      node.type = 'text/javascript';
      node.async = true;
      node.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }
}
Robert King
quelle
1
Das fühlt sich irgendwie zwielichtig an
Mustafa
2

Die Lösung von @ rahul-kumar funktioniert gut für mich, aber ich wollte meine Javascript-Funktion in meinem Typoskript aufrufen

foo.myFunctions() // works in browser console, but foo can't be used in typescript file

Ich habe es behoben, indem ich es in meinem Typoskript deklariert habe:

import { Component } from '@angular/core';
import { ScriptService } from './script.service';
declare var foo;

Und jetzt kann ich foo überall in meiner Typografie-Datei aufrufen

Z3nk
quelle
Wenn ich mehrere Skripte foo, foo1, foo2 importiere und nur während der Ausführungszeit weiß, wie die Deklaration dynamisch ausgeführt wird?
Natrayan
2

In meinem Fall habe ich sowohl die jsals auch die css visjsDateien mit der oben beschriebenen Technik geladen - was großartig funktioniert. Ich rufe die neue Funktion von aufngOnInit()

Hinweis: Ich konnte es nicht zum Laden bringen, indemicheinfach ein<script>und<link>-Tag zur HTML-Vorlagendateihinzufügte.

loadVisJsScript() {
  console.log('Loading visjs js/css files...');
  let script = document.createElement('script');
  script.src = "../../assets/vis/vis.min.js";
  script.type = 'text/javascript';
  script.async = true;
  script.charset = 'utf-8';
  document.getElementsByTagName('head')[0].appendChild(script);    
	
  let link = document.createElement("link");
  link.type = "stylesheet";
  link.href = "../../assets/vis/vis.min.css";
  document.getElementsByTagName('head')[0].appendChild(link);    
}

bob.mazzo
quelle
Ich möchte die CSS-Datei von einer externen Webquelle laden. Derzeit wird der Fehler "Lokale Ressource darf nicht geladen werden" angezeigt. Bitte vorschlagen.
Karan
Ich habe es so versucht. Obwohl es gut für
Skriptdateien
2

Hallo, Sie können Renderer2 und elementRef mit nur wenigen Codezeilen verwenden:

constructor(private readonly elementRef: ElementRef,
          private renderer: Renderer2) {
}
ngOnInit() {
 const script = this.renderer.createElement('script');
 script.src = 'http://iknow.com/this/does/not/work/either/file.js';
 script.onload = () => {
   console.log('script loaded');
   initFile();
 };
 this.renderer.appendChild(this.elementRef.nativeElement, script);
}

Die onloadFunktion kann verwendet werden, um die Skriptfunktionen aufzurufen, nachdem das Skript geladen wurde. Dies ist sehr nützlich, wenn Sie die Aufrufe in ngOnInit () ausführen müssen.

Hetdev
quelle
1

@ d123546 Ich hatte das gleiche Problem und konnte es jetzt mit ngAfterContentInit (Lifecycle Hook) in der Komponente wie folgt zum Laufen bringen:

import { Component, OnInit, AfterContentInit } from '@angular/core';
import { Router } from '@angular/router';
import { ScriptService } from '../../script.service';

@Component({
    selector: 'app-players-list',
    templateUrl: './players-list.component.html',
    styleUrls: ['./players-list.component.css'],
    providers: [ ScriptService ]
})
export class PlayersListComponent implements OnInit, AfterContentInit {

constructor(private router: Router, private script: ScriptService) {
}

ngOnInit() {
}

ngAfterContentInit() {
    this.script.load('filepicker', 'rangeSlider').then(data => {
    console.log('script loaded ', data);
    }).catch(error => console.log(error));
}
Waseem
quelle
0

eine Probe kann sein

Datei script-loader.service.ts

import {Injectable} from '@angular/core';
import * as $ from 'jquery';

declare let document: any;

interface Script {
  src: string;
  loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
public _scripts: Script[] = [];

/**
* @deprecated
* @param tag
* @param {string} scripts
* @returns {Promise<any[]>}
*/
load(tag, ...scripts: string[]) {
scripts.forEach((src: string) => {
  if (!this._scripts[src]) {
    this._scripts[src] = {src: src, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach((src) => promises.push(this.loadScript(tag, src)));

return Promise.all(promises);
}

 /**
 * Lazy load list of scripts
 * @param tag
 * @param scripts
 * @param loadOnce
 * @returns {Promise<any[]>}
 */
loadScripts(tag, scripts, loadOnce?: boolean) {
loadOnce = loadOnce || false;

scripts.forEach((script: string) => {
  if (!this._scripts[script]) {
    this._scripts[script] = {src: script, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach(
    (script) => promises.push(this.loadScript(tag, script, loadOnce)));

return Promise.all(promises);
}

/**
 * Lazy load a single script
 * @param tag
 * @param {string} src
 * @param loadOnce
 * @returns {Promise<any>}
 */
loadScript(tag, src: string, loadOnce?: boolean) {
loadOnce = loadOnce || false;

if (!this._scripts[src]) {
  this._scripts[src] = {src: src, loaded: false};
}

return new Promise((resolve, reject) => {
  // resolve if already loaded
  if (this._scripts[src].loaded && loadOnce) {
    resolve({src: src, loaded: true});
  }
  else {
    // load script tag
    let scriptTag = $('<script/>').
        attr('type', 'text/javascript').
        attr('src', this._scripts[src].src);

    $(tag).append(scriptTag);

    this._scripts[src] = {src: src, loaded: true};
    resolve({src: src, loaded: true});
  }
 });
 }
 }

und Verwendung

zuerst injizieren

  constructor(
  private _script: ScriptLoaderService) {
  }

dann

ngAfterViewInit()  {
this._script.loadScripts('app-wizard-wizard-3',
['assets/demo/default/custom/crud/wizard/wizard.js']);

}

oder

    this._script.loadScripts('body', [
  'assets/vendors/base/vendors.bundle.js',
  'assets/demo/default/base/scripts.bundle.js'], true).then(() => {
  Helpers.setLoading(false);
  this.handleFormSwitch();
  this.handleSignInFormSubmit();
  this.handleSignUpFormSubmit();
  this.handleForgetPasswordFormSubmit();
});
unos baghaii
quelle
0
import { Injectable } from '@angular/core';
import * as $ from 'jquery';

interface Script {
    src: string;
    loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
    public _scripts: Script[] = [];

    /**
     * @deprecated
     * @param tag
     * @param {string} scripts
     * @returns {Promise<any[]>}
     */
    load(tag, ...scripts: string[]) {
        scripts.forEach((src: string) => {
            if (!this._scripts[src]) {
                this._scripts[src] = { src: src, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(src => promises.push(this.loadScript(tag, src)));

        return Promise.all(promises);
    }

    /**
     * Lazy load list of scripts
     * @param tag
     * @param scripts
     * @param loadOnce
     * @returns {Promise<any[]>}
     */
    loadScripts(tag, scripts, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        scripts.forEach((script: string) => {
            if (!this._scripts[script]) {
                this._scripts[script] = { src: script, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(script => promises.push(this.loadScript(tag, script, loadOnce)));

        return Promise.all(promises);
    }

    /**
     * Lazy load a single script
     * @param tag
     * @param {string} src
     * @param loadOnce
     * @returns {Promise<any>}
     */
    loadScript(tag, src: string, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        if (!this._scripts[src]) {
            this._scripts[src] = { src: src, loaded: false };
        }

        return new Promise((resolve, _reject) => {
            // resolve if already loaded
            if (this._scripts[src].loaded && loadOnce) {
                resolve({ src: src, loaded: true });
            } else {
                // load script tag
                const scriptTag = $('<script/>')
                    .attr('type', 'text/javascript')
                    .attr('src', this._scripts[src].src);

                $(tag).append(scriptTag);

                this._scripts[src] = { src: src, loaded: true };
                resolve({ src: src, loaded: true });
            }
        });
    }

    reloadOnSessionChange() {
        window.addEventListener('storage', function(data) {
            if (data['key'] === 'token' && data['oldValue'] == null && data['newValue']) {
                document.location.reload();
            }
        });
    }
}
Aniket
quelle