crear - Cargue dinĂ¡micamente un archivo javascript externo desde un componente angular
crear proyecto angular 6 (9)
He hecho este fragmento de código
addJsToElement(src: string): HTMLScriptElement {
const script = document.createElement(''script'');
script.type = ''text/javascript'';
script.src = src;
this.elementRef.nativeElement.appendChild(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'');
}
EDITAR: con el nuevo renderizador Api se puede escribir así
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;
}
Estoy creando una aplicación Angular usando Angular 4 y la CLI. Estoy tratando de agregar el widget de búsqueda SkyScanner en uno de mis componentes.
Ejemplo de widget de Skyscanner
Parte de la implementación requiere la adición de un nuevo script externo:
<script src="https://widgets.skyscanner.net/widget-server/js/loader.js" async></script>
No estoy seguro de la forma correcta de hacer referencia a este archivo. Si agrego el script a mi archivo index.html, el widget no se carga a menos que se realice una actualización completa de la página. Supongo que el script intenta manipular el DOM en la carga y los elementos no existen cuando se ejecuta el script.
¿Cuál es la forma correcta de cargar el script solo cuando se carga el componente que contiene el widget Skyscanner?
Intente cargar JavaScript externo en la carga de componentes de la siguiente manera:
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);
}
}
}
La respuesta aceptada es correcta, pero no funcionará porque el navegador tarda un poco más en analizar el script después de descargarlo. Por lo tanto, si se usa alguna variable del script cargado, entonces debe usarse en el evento de carga del elemento de script html recién creado. He mejorado la respuesta aceptada como se menciona a continuación:
loadAPI: Promise<any>;
constructor() {
this.loadAPI = new Promise((resolve) => {
let node = this.loadScript();
if (node) {
node.onload = () => {
resolve(true);
};
} else {
resolve(true);
}
});
}
ngOnInit() {
this.loadAPI
.then((flag) => {
//Do something when script is loaded and parsed by browser
});
}
loadScript() {
let node = undefined;
let isFound = false;
const scripts = document.getElementsByTagName(''script'')
for (let i = 0; i < scripts.length; ++i) {
// Check if script is already there in html
if (scripts[i].getAttribute(''src'') != null && scripts[i].getAttribute(''src'').includes("loader")) {
isFound = true;
}
}
if (!isFound) {
const dynamicScript = ''https://widgets.skyscanner.net/widget-server/js/loader.js'';
node = document.createElement(''script'');
node.src = dynamicScript;
node.type = ''text/javascript'';
node.async = false;
node.charset = ''utf-8'';
document.getElementsByTagName(''head'')[0].appendChild(node);
return node;
}
return node;
}
Nota: ¡Esto es especialmente para enlaces js externos! Paso 1. ¡Se recomienda agregar su script angular al archivo index.html en la parte inferior de su cuerpo! Intenté todas las otras formas pero fallé.
<!-- 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>
A continuación, hay dos formas de hacer esto ... En Anguar5, use dentro de la carpeta de componentes en la parte superior de este código
declare var feather:any;
y luego dentro de tu clase llama al método que necesitas. Por ejemplo
//FileName: dashboard.component.ts
import { Component, OnInit } from ''@angular/core'';
declare var feather:any;
export class DashboardComponent implements OnInit{
ngOnInit(){
feather.replace();
}
}
¡y esto debería ejecutar tu código! La otra forma que podría funcionar en la versión anterior. No he comprobado!
//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 no está recibiendo mi código, pruebe también este link .
¡Espero que esto ayude!
Puede crear su propia directiva para cargar el script de la siguiente manera
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);
}
}
Y puede usarlo en cualquier lugar de su plantilla de componentes como se muestra a continuación
<i appLoadScript [script]="''script_file_path''"></i>
Por ejemplo, para cargar dinámicamente JQuery en su componente, inserte el siguiente código en la plantilla de su componente
<i appLoadScript [script]="''/assets/baker/js/jquery.min.js''"></i>
Puedes hacer una cosa
si tienes angular-cli.json
entonces puedes declarar al script
me gusta
"scripts": ["../src/assets/js/loader.js"]
Y luego declara skyscanner en tu componente
me gusta
declare var skyscanner:any;
¡Eso es!
Espero que esto te ayude
Tuve el mismo problema, pero en mi caso, estaba importando 10 bibliotecas al final del archivo html, y estas bibliotecas tienen muchos métodos, escuchas, eventos y más, y en mi caso no necesitaba llame a un método específicamente.
El ejemplo sobre lo que tenía:
<!-- 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 -->
Como se mencionó, no funcionó. Entonces, encuentro algo que me ayudó: la respuesta de Milad
-
Elimine las llamadas de script en app.component.html. Debe vincular estos scripts en el archivo app.component.ts.
-
En ngOnInit (), use un método para agregar las bibliotecas, por ejemplo:
``
<!-- 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);
}
}
Funciona para mi. Yo uso Angular 6, espero que ayude.
Un poco tarde, pero prefiero hacerlo de esta manera (servicio) ...
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'' });
}
});
}
}
Luego, en mi componente, podría hacer algo como:
ngOnInit() {
this.fileInjectorService.loadJS(''script-a'', ''script-c'').then(data => {
// Loaded A and C....
}).catch(error => console.log(error));
}
Probado en Angular 6/7
agregue
loader.js
a su carpeta de activos y luego en su
angular-cli.json
"scripts": ["./src/assets/loader.js",]
luego agregue esto a sus
typings.d.ts
declare var skyscanner:any;
y podrás usarlo
skyscanner.load("snippets","2");