Cover image for Angular2でSharedServiceを作りたい
angularangular2typescript

Angular2でSharedServiceを作りたい

February 28, 2016

4 min read

mitsuruogMitsuru Ogawa

SPA を構築する場合、Component をまたがったデータの共有をどのように実現するかが重要になってきます。
Angular1 の場合は、SharedService を利用するケースが多かったです。
そこで Angular2 でも試してみようとしたところ、少し勝手が違ったので自分用メモを残しておきます。

結論

  • Angular2 では基本的に@Injectable()の DI は新規のインスタンスを生成します。
  • Singleton で扱いたい場合は、bootstrap(.., [ServiceA,ServiceB])で DI すること。

サンプル

Angular2 の公式ページでよく利用される HeroList を例に説明します。

  • 画面の component は一覧(HeroListComponent)と詳細(HeroDetailComponent)の 2 つ。
  • Hero 一覧データは HeroService に格納され、各 component は HeroService を参照する。

簡単な図に示すとこのような構造をしていると仮定します。

失敗パターン

すべてのサンプルはこちら
plnkr

失敗パターンでは、HeroDetailComponent にて Hero を削除しても消えません。
これは HeroDetailComponent のprovidersで HeroService を DI した場合、新規でインスタンスを生成してしまうためです。 結果、HeroListComponent と HeroDetailComponent では、別の HeroService のインスタンスを参照していることになっています。

HeroDetailComponent で@Componentを DI している箇所を抜粋します。

hero-detail.component.ts

import {Component,  Input}  from 'angular2/core';
import {Hero, HeroService}   from './hero.service';

@Component({
  selector: 'hero-detail',
  template: `
  <span class="badge">{{hero.id}}</span> {{hero.name}}
  <button (click)="remove()">remove</button>
  `,
  providers:  [HeroService]  // <- ここ
})
export class HeroDetailComponent implements OnInit  {
  @Input() hero: Hero;
  constructor(private service:HeroService){ }
  remove() {
    this.service.remove(this.hero);
  }
}

成功パターン

すべてのサンプルはこちら
plnkr

こちらは SharedService として動作しているパターンです。bootstrap(.., [ServiceA,ServiceB])で HeroService を指定することで Singleton として扱うことができます。
HeroDetailComponent で Hero を削除した場合、HeroListComponent の一覧も消えます。

main.ts

import { bootstrap } from "angular2/platform/browser";

import { AppComponent } from "./app.component";
import { Hero, HeroService } from "./heroes/hero.service";

bootstrap(AppComponent, [HeroService]);

まとめ

Angular1 っぽい SharedService の作り方でした。
正直、Two-way-binding と SharedService を利用した、手続き型っぽいやり方が Angular2 で最良の方法がどうかはわかりません。
Angular2 でのベストプラクティスについてはまだ手探りな感じがします。

とはいえ、Angular1 を慣れている方であれば、Angular2 でも Component 間のデータ共有は SharedService でできることが分かりました。

refs Angular2 "Services" how to @inject one service into another (singletons) - Stack Overflow