Динамическое добавление элемента script в Angular
Не часто при разработке SPA приложения появляется задача с динамическим добавлением JS файла на страницу.
В данной статье рассмотрим несколько возможных способов динамического добавления script
в Angular.
Динамическое добавление css link и js script
Добавление link и script нативным способом в JavaScript
// Добавление стилей
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css';
document.head.appendChild(link);
// Добавление скрипта
const script = document.createElement('script');
script.src = 'https://code.jquery.com/jquery-3.3.1.slim.min.js';
document.body.appendChild(script)
Певрый способ
Примитивный способ. Аналогичен нативной вставке скрипта в тело документа, описанным чуть выше.
constructor(
@Inject(DOCUMENT) private document: Document,
private renderer2: Renderer2
) {}
ngOnInit(): void {
const textScript = this.renderer2.createElement('script');
textScript.src = 'https://code.jquery.com/jquery-3.3.1.slim.min.js';
this.renderer2.appendChild(this.document.body, textScript);
const srcScript = this.renderer2.createElement('script');
srcScript.type = 'text/javascript';
srcScript.text = `
(function() {
console.log('Hello from Siberia!')
}());
`;
this.renderer2.appendChild(this.document.body, srcScript);
}
Второй способ
Более продвинутый способ: завернуть в Promise
.
ngOnInit() {
this.loadScript('https://code.jquery.com/jquery-3.3.1.slim.min.js').then(
() => this.loadTextScript(`
setTimeout(() => {
$( "#promise-based" ).html( "PromiseBasedComponent..." )
}, 2000);
`)
);
}
loadTextScript(text: string) {
return new Promise(resolve => {
const script = this.renderer2.createElement('script');
script.text = text;
this.renderer2.appendChild(this.document.body, script);
resolve();
});
}
loadScript(url: string) {
return new Promise((resolve, reject) => {
const script = this.renderer2.createElement('script');
script.src = url;
script.onload = resolve;
script.onerror = reject;
this.renderer2.appendChild(this.document.body, script);
});
}
Трейти способ
Способ с использование ReplaySubject в сервисе:
import { Injectable, Inject } from '@angular/core';
import { ReplaySubject, Observable } from 'rxjs';
import { DOCUMENT } from '@angular/common';
@Injectable()
export class LazyLoadingScriptService {
_loadedLibraries: { [url: string]: ReplaySubject<any> } = {};
constructor(@Inject(DOCUMENT) private readonly document: any) { }
loadScript(url: string): Observable<any> {
if (this._loadedLibraries[url]) {
return this._loadedLibraries[url].asObservable();
}
this._loadedLibraries[url] = new ReplaySubject();
const script = this.document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = () => {
this._loadedLibraries[url].next();
this._loadedLibraries[url].complete();
};
this.document.body.appendChild(script);
return this._loadedLibraries[url].asObservable();
}
}
/* Usage */
this.lazyLoadService.loadScript('/assets/scripts/some-script.js').subscribe(() => {
// code
});