LoginSignup
3
4

More than 5 years have passed since last update.

[Angular] ServiceからEventEmitterをつかってComponentにイベント通知する

Last updated at Posted at 2017-06-23

EventEmitterComponent内でしか使えないという思い込みがありました。

さんぷる

Google Charts API をロードするサービス。

gmazzamuto/ng2-google-charts

を参考に作成しています。

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.logfalse
その後、load()が完了して、再びイベントが発行され、trueとなる 。

これで、いままでできていなかったことが実現できそう。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4