Skip to content

Instantly share code, notes, and snippets.

@LayZeeDK
Created July 3, 2020 23:46
Show Gist options
  • Save LayZeeDK/5c30299be46ce5215947945d50506b87 to your computer and use it in GitHub Desktop.
Save LayZeeDK/5c30299be46ce5215947945d50506b87 to your computer and use it in GitHub Desktop.
Angular script service for loading JavaScript script files in the browser, using RxJS.
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, Renderer2 } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
import { switchMapTo, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class ScriptService {
private scriptLoaded = new Map<string, Observable<void>>();
constructor(
@Inject(DOCUMENT) private document: Document,
private renderer: Renderer2
) {}
load(url: string): Observable<void> {
if (this.scriptLoaded.has(url)) {
return this.scriptLoaded.get(url) as Observable<void>;
}
const loaded = new ReplaySubject<void>(1);
const loaded$ = loaded.asObservable();
this.scriptLoaded.set(url, loaded$);
return this.loadScript(url).pipe(
tap({
error: (error: ErrorEvent) => {
loaded.error(error);
},
next: () => {
loaded.next();
loaded.complete();
},
}),
switchMapTo(loaded$)
);
}
private loadScript(url: string): Observable<void> {
return new Observable((subscriber) => {
const script: HTMLScriptElement = this.renderer.createElement('script');
script.type = 'application/javascript';
script.async = true;
script.src = url;
const appendScript = () => {
this.renderer.appendChild(this.document.body, script);
};
const removeScript = () => {
this.renderer.removeChild(this.document.body, script);
};
const onLoad = () => {
teardown();
subscriber.next();
subscriber.complete();
};
const onError = (error: ErrorEvent) => {
teardown();
subscriber.error(error);
};
const removeOnLoad = this.renderer.listen(script, 'load', onLoad);
const removeOnError = this.renderer.listen(script, 'error', onError);
let isDestroyed = false;
const teardown = () => {
if (isDestroyed) {
return;
}
removeScript();
removeOnLoad();
removeOnError();
isDestroyed = true;
};
appendScript();
return teardown;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment