[英]How to load a 3rd party script from web dynamically into Angular2 component
I am trying to load a 3rd party script from web, instead of making a local copy of it and be able to use the 3rd party script's global variables and functions after the script loads. 我正在尝试从Web加载第三方脚本,而不是对其进行本地复制,并且能够在脚本加载后使用第三方脚本的全局变量和函数。
Update : 更新 :
Issue: Component below is not loading the script from web 问题:以下组件无法从Web加载脚本
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!!' } }
You can dynamically load JS scripts and libraries on demand in your Angular 2/4 project using this technique. 您可以使用此技术在Angular 2/4项目中按需动态加载JS脚本和库。
Create ScriptStore
in script.store.ts that will contain the path of the script either locally or on a remote server and a name that will be used to load the script dynamically: 在script.store.ts中创建
ScriptStore
,它将包含本地或远程服务器上脚本的路径以及将用于动态加载脚本的名称 :
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'}
];
Create script.service.ts to provide ScriptService
as an injectable service that will handle the loading of script files. 创建script.service.ts以提供
ScriptService
作为可注入服务,该服务将处理脚本文件的加载。 Include this code: 包含以下代码:
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);
}
});
}
}
Inject ScriptService
wherever you need it and load scripts like this: 在需要的地方注入
ScriptService
并加载如下脚本:
constructor(
private scriptService: ScriptService
) { }
ngOnInit() {
this.scriptService.load('filepicker', 'rangeSlider').then(data => {
console.log('script loaded ', data);
}).catch(error => console.log(error));
}
There are two ways that this can be accomplished. 有两种方法可以实现。
.d.ts
and are basically an interface for the functions of the script. .d.ts
结尾,并且基本上是脚本功能的接口。 If there is not a pre-defined type definition file you can create one your self with the functions that you need. any
; any
; Example using AutoMapperTS: 使用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);
}
}
(The reference in this example may be different depending on your editor. This example is using Visual Studio. Try dragging the file you want to reference onto the editor window to see if your IDE will create the reference for you.) (此示例中的引用可能会有所不同,具体取决于您的编辑器。此示例使用的是Visual Studio。尝试将要引用的文件拖到编辑器窗口中,以查看IDE是否会为您创建引用。)
Declaration: 宣言:
declare var automapper: any;
@Component({
selector: "my-app",
})
export class AppComponent {
constructor() {
automapper.map("JSON", "myType", jsonObj);
}
}
The 3rd party JS file can be loaded using the standard <script>
tag import. 可以使用标准
<script>
标签导入来加载第三方JS文件。 The above methods are for the TS compiler so that it won't fail with an unknown variable exception. 以上方法适用于TS编译器,因此不会因未知变量异常而失败。
I have modified Rahul Kumar's answer so that it uses Observables instead: 我修改了Rahul Kumar的答案,以便它改用Observables:
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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.