AngularにはService(サービス)という仕組みがあります。
その実体は単一のクラスです。
@Injectable({ providedIn: 'root' }) export class HeroService { private heroesUrl = 'api/heroes'; constructor( private http: HttpClient, private messageService: MessageService ) {} getHeroes(): Observable<Hero[]> { ... } getHero(id: number): Observable<Hero> { ... } }
Injectableデコレータを利用してクラス定義し、Angularアプリケーションに登録することでコンポーネントやサービスで利用可能になります。
なぜサービスが必要なのか?
どうしてAngularにはサービスが必要なのでしょうか?
本来コンポーネントはデータの受け渡しのみに集中するべきです。複雑なデータ整形処理、コンポーネントで重複したAPI通信、エラーハンドリングなど、何も考えずにコンポーネントに追加していっては次第に実装コードは肥大化し、それにつれて管理コストは上がり、コードの見通しも悪いため変更に時間がかかるようになってしまいます。
そこでサービスの出番です。コンポーネントにあるビジネスロジックをサービスに切り出すことで、関心事を分離でき、それに加えコンポーネント間の共通処理をまとめることができます。
サービスのおかげでアプリケーションの秩序が保たれるのです。
またサービスはクラスなので、自身にデータを保持することができます。HttpClientを使用した際のエラーメッセージを保持する際などに、コンポーネントではなくサービスにメッセージを持たせればどこからでも参照できて便利です。
サービスの使いかた
冒頭でも触れたとおり、サービスはAngularアプリに登録しなければ利用できませんが、あまり気にすることはありません。
Angular CLIで生成したサービスなら、Injectableデコレータ内で providedIn: 'root'
が指定されているため自動的にAngularアプリ全体で利用することができます。
@Injectable({ providedIn: 'root' }) export class HeroService { }
providedIn: ‘root’ を指定しない方法
providedIn: 'root'
の指定を無くして、モジュールやコンポーネントの中だけに利用範囲を限定させる方法もあります。
モジュールで利用する場合
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, ], providers: [ HeroService <- ], bootstrap: [AppComponent] }) export class AppModule { }
コンポーネントで利用する場合
@Component({ selector: 'app-hero-detail', templateUrl: './hero-detail.component.html', styleUrls: ['./hero-detail.component.css'], providers: [HeroService] <- }) export class HeroDetailComponent implements OnInit { }
Providers配列にサービスを登録します。遅延読み込み(LazyLoading)を利用する際に便利です。
このときの注意点は、サービスはAngularアプリ内ではシングルトンであるべきだということを覚えておいてください。同じサービスを別々に有効にしてしまうと、コンポーネントからの参照先が一致せず意図しない動作になる可能性が高いため絶対に避けてください。
一般的に推奨されているのは providedIn: 'root'
を指定する方法です。
難しいことが苦手な方は、基本的に providedIn: 'root'
を指定しておきましょう。