usar pagina incluir funcion externo ejecutar div cargar antes agregar javascript angular typescript ecmascript-6

pagina - javascript en angular 4



¿Cómo cargar scripts externos dinámicamente en Angular? (14)

¡Tengo una buena forma de cargar scripts dinámicamente! Ahora uso ng6, echarts4 (> 700Kb), ngx-echarts3 en mi proyecto. cuando los uso con los documentos de ngx-echarts, necesito importar echarts en angular.json: "scripts": ["./ node_modules / echarts / dist / echarts.min.js"], por lo tanto, en el módulo de inicio de sesión, página mientras se cargan los scripts .js, este es un archivo grande! No lo quiero

Entonces, creo que angular carga cada módulo como un archivo, puedo insertar un enrutador para precargar js, ¡y luego comenzar la carga del módulo!

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

Luego, en submodule-routing.module.ts, importe este PreloadScriptResolver:

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

Este código funciona bien y promete que: después de cargar el archivo js, ​​¡el módulo comenzará a cargar! este Resolver puede usar en muchos enrutadores

Tengo este módulo que compone la biblioteca externa junto con lógica adicional sin agregar la etiqueta <script> directamente en index.html:

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 {...}

Noté que la import mediante la especificación ES6 es estática y se resuelve durante la transcripción de TypeScript en lugar del tiempo de ejecución.

¿De todos modos para que sea configurable para que el archivo.js se cargue desde CDN o carpeta local? ¿Cómo decirle a Angular 2 que cargue un script dinámicamente?


@ d123546 Me enfrenté al mismo problema y lo puse a funcionar ahora usando ngAfterContentInit (Lifecycle Hook) en el componente de esta manera:

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


En mi caso, he cargado los archivos js y css visjs utilizando la técnica anterior, que funciona muy bien. Llamo a la nueva función desde ngOnInit()

Nota: No pude hacer que se cargara simplemente agregando una etiqueta <script> y <link> al archivo de plantilla html.

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


Esto podría funcionar. Este código agrega dinámicamente la etiqueta <script> al head del archivo html al hacer clic en el botón.

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


He hecho este fragmento de código con la nueva API de renderizador

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

Y luego llámalo así

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

StackBlitz


He modificado la respuesta de @rahul kumars, para que use Observables en su lugar:

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 }


La solución de @ rahul-kumar funciona bien para mí, pero quería llamar a mi función javascript en mi mecanografiado

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

Lo arreglé declarándolo en mi mecanografiado:

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

Y ahora, puedo llamar a foo en cualquier parte de mi archivo de mecanografía


Otra opción más sería utilizar el paquete scriptjs para el caso que

le permite cargar recursos de script a pedido desde cualquier URL

Ejemplo

Instala el paquete:

npm i scriptjs

y definiciones de tipo para scriptjs :

npm install --save @types/scriptjs

Luego importe el $script.get() :

import { get } from ''scriptjs'';

y finalmente cargar el recurso de script, en nuestro caso la biblioteca de Google Maps:

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

Demo


Puede cargar múltiples scripts dinámicamente como este en su archivo component.ts :

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

y llama a este método dentro del constructor,

constructor() { this.loadScripts(); }

Nota: Para que se carguen más scripts dinámicamente, agréguelos a la matriz dynamicScripts .


Puede usar la siguiente técnica para cargar dinámicamente scripts y bibliotecas JS a pedido en su proyecto Angular.

script.store.ts contendrá la ruta del script localmente o en un servidor remoto y un nombre que se usará para cargar el script dinámicamente

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 es un servicio inyectable que manejará la carga del script, copie script.service.ts tal como está

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

Inyecte este ScriptService donde lo necesite y cargue js libs como este

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


Si usa system.js, puede usar System.import() en tiempo de ejecución:

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

Si usa webpack, puede aprovechar al máximo su sólido soporte de división de código con require.ensure :

export class MyAppComponent { constructor() { require.ensure([''path/to/your/module''], require => { let yourModule = require(''path/to/your/module''); yourModule.someFunction(); }); } }


Una solución universal angular; Necesitaba esperar a que un elemento en particular estuviera en la página antes de cargar un script para reproducir un video.

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


una muestra puede ser

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

y uso

primera inyección

constructor( private _script: ScriptLoaderService) { }

entonces

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

o

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


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