2016-06-09 8 views
9

Ich versuche, ein 3rd-Party-Skript aus dem Web zu laden, anstatt eine lokale Kopie davon zu erstellen und die globalen Variablen und Funktionen des 3rd-Party-Skripts zu verwenden Das Skript wird geladen.Wie man ein 3rd-Party-Skript aus dem Web dynamisch in die Angular2-Komponente lädt

aktualisieren:

  • Hier ist ein Beispiel das, was ich in einfacher JavaScript zu erreichen versuchen, wo Dialog klicken Sie auf Visa Checkout-Schaltfläche öffnet Visa Checkout: Plunker JS link
  • Hier ist die Angular2 Version es, wo ich Hilfe benötigen: Plunker Angular2 link

Ausgabe: Komponente unten wird geladen nicht das Skript von w eb

import {Component} from '@angular/core' 
 

 
@Component({ 
 
    selector: 'custom', 
 
    providers: [], 
 
    template: ` 
 
    <div> 
 
     <h2>{{name}}</h2> 
 
     <img class="v-button" role="button" alt="Visa Checkout" src="https://sandbox.secure.checkout.visa.com/wallet-services-web/xo/button.png"> 
 
     <script src="https://sandbox-assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js"> 
 
</script> 
 
    </div> 
 
    ` 
 
}) 
 
export class CustomComponent { 
 
    constructor() { 
 
    this.name = 'Custom Component works!!' 
 
    } 
 
}

Antwort

2

Es gibt zwei Möglichkeiten, wie dies erreicht werden kann.

  1. Referenzieren Sie eine Typdefinitionsdatei für das hinzuzufügende 3rd-Party-Skript. Typdefinitionsdateien enden normalerweise in .d.ts und sind im Grunde eine Schnittstelle für die Funktionen des Skripts. Wenn es keine vordefinierte Typdefinitionsdatei gibt, können Sie sich selbst mit den Funktionen, die Sie benötigen, erstellen. (Ich bevorzuge diese Methode, weil einige IDEs Ihnen die Methodensignatur als Teil des Intellisense geben)
  2. Erstellen Sie eine Variable an der Spitze der TypeScript-Klasse, die die Bibliothek darstellt, die Sie mit einem Typ any verwenden;

Beispiel mit AutoMapperTS:

Type Definition:..

/// <reference path="../node_modules/automapper-ts/dist/automapper.d.ts" /> 

@Component({ 
    selector: "my-app", 
}) 
export class AppComponent { 
    constructor() { 
     automapper.map("JSON", "myType", jsonObj); 
    } 
} 

(Die Bezugnahme in diesem Beispiel kann auf Ihrem Editor abhängig unterschiedlich sein Dieses Beispiel Visual Studio verwendet Versuchen Sie ziehen die Datei, auf die Sie im Editorfenster verweisen möchten, um zu sehen, ob Ihre IDE die Referenz für Sie erstellt.)

Erklärung:

declare var automapper: any; 

@Component({ 
    selector: "my-app", 
}) 
export class AppComponent { 
    constructor() { 
     automapper.map("JSON", "myType", jsonObj); 
    } 
} 

Die 3rd-Party-JS-Datei geladen werden kann, den Standard <script> Tag Import verwenden. Die obigen Methoden gelten für den TS-Compiler, so dass er bei einer unbekannten Variablenausnahme nicht fehlschlägt.

+0

Dank für die schnelle Antwort. Ich bin neu bei Angular und habe deine Antwort nicht ganz verstanden. Können Sie sich meine aktualisierte Frage mit Plunker-Beispielen ansehen? Ich schätze Hilfe! – Rishi

+0

Ich habe mir Ihren Plunker angeschaut, aber die Seite ist gerade unten. Das erste Problem, das ich sehe, ist, dass Sie keine "Skript" -Tags in die Vorlage einer Komponente aufnehmen sollten, da Angular diese ausblendet. Skripte für den dritten Teil sollten in die 'index.html' geladen werden. Ich werde einen anderen Blick werfen, sobald Plunker wieder da ist. –

+0

Obwohl ich gerne sehen würde, wie es funktioniert, indem ich das Skript in index.html einfüge, würde ich es vorziehen, das Skript zusammen mit dem my-component zu laden. In diesem speziellen Fall muss ich auch auf die globalen Variablen des Skripts zugreifen, das vom Web in my-component geladen wird. – Rishi

9

Sie können JS-Skripte und Bibliotheken bei Bedarf in Ihrem Angular 2/4-Projekt mithilfe dieser Technik dynamisch laden.

Erstellen Sie ScriptStore in script.store.ts, die den Pfad des Skripts entweder lokal oder auf einem Remote-Server und einen Namen enthalten, die verwendet wird, um das Skript dynamisch zu laden:

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

erstellen script.service.ts, um ScriptService als injizierbaren Dienst bereitzustellen, der das Laden von Skriptdateien verarbeiten wird. Fügen Sie diesen Code:

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

declare var document: any; 

@Injectable() 
export class Script { 

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

} 

Inject ScriptService wo Sie es und Last-Skripte wie diese benötigen:

constructor(
    private scriptService: ScriptService 
) { } 

ngOnInit() { 
    this.scriptService.load('filepicker', 'rangeSlider').then(data => { 
     console.log('script loaded ', data); 
    }).catch(error => console.log(error)); 
} 
2

ich geändert haben Rahul Kumar's answer so dass es Observable verwendet stattdessen:

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 
} 
+0

Prost ... es funktioniert zu laden ... aber wie würde ich es ausführen? und die Async-Funktionalität nachahmen? –