EventEmitter
はComponent
内でしか使えないという思い込みがありました。
さんぷる
Google Charts API をロードするサービス。
を参考に作成しています。
google-charts-loader.service.ts
const LOAD_JS = "//www.gstatic.com/charts/loader.js" as string;
declare var google: any;
import { Injectable, EventEmitter } from "@angular/core";
@Injectable()
export class GoogleChartsLoaderService
{
private scriptIsLoading: boolean = false;
public scriptLoadingNotifier: EventEmitter<boolean> = new EventEmitter<boolean>();
private _chartType: string = "ColumnChart";
private chartPackages: {[id: string]: string} = {
ColumnChart : "corechart",
};
set chartType(chartType: string)
{
this._chartType = chartType;
}
public load(): Promise<any>
{
return new Promise((resolve: any = Function.prototype, reject: any = Function.prototype) => {
this.loadScript()
.then(() => {
google.charts.load("current", {
packages : [this.chartPackages[this._chartType]],
callback : resolve,
})
})
.catch(err => console.error("Google charts script could not be loaded."));
});
}
private loadScript(): Promise<any>
{
return new Promise((resolve: any = Function.prototype, reject: any = Function.prototype) => {
if (typeof google !== "undefined") {
resolve();
} else if (! this.scriptIsLoading) {
let script = document.createElement("script");
script.src = LOAD_JS;
script.async = true;
script.defer = true;
script.onload = () => {
this.scriptIsLoading = true;
this.scriptLoadingNotifier.emit(this.scriptIsLoading);
resolve();
};
script.onerror = () => {
this.scriptIsLoading = false;
this.scriptLoadingNotifier.emit(this.scriptIsLoading);
reject();
};
document.body.appendChild(script);
}
});
}
public check(): void
{
this.scriptLoadingNotifier.emit(this.scriptIsLoading);
}
}
イベントのうけとり
EventEmitter.subscribe() を利用して Componentでイベントをうけとる。
sample.component.ts
import { Component, OnInit } from "@angular/core";
import { GoogleChartsLoaderService } from "./google-charts-loader.service";
@Component({
selector : "my-app",
template : "<h1>Hello Angular</h1>",
})
export class MyAppComponent implements OnInit
{
public constructor(
private googleChartsLoaderService: GoogleChartsLoaderService
) {
console.log("constructor()");
this.googleChartsLoaderService
.scriptLoadingNotifier
.subscribe((data: boolean) => console.log("subscribe()", data));
}
/**
* Angular LifeCycle
*/
public ngOnInit()
{
console.log("ngOnInit()");
this.googleChartsLoaderService.load();
this.googleChartsLoaderService.check();
}
}
コンソール
constructor()
ngOnInit()
subscribe() false
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
subscribe() true
動作
load()
が先に呼ばれるけど、非同期処理なのでcheck()
がすぐに呼ばれる。
この時点でthis.scriptIsLoading === false なので、console.log
はfalse
その後、load()
が完了して、再びイベントが発行され、true
となる 。
これで、いままでできていなかったことが実現できそう。