はじめに
こちらの記事 でコンポーネントの作成について触れたので、本記事で Angular CLI でサービスの作り方についてみていく。
更新情報
2021/01/04
- 記事内で扱ったコードを Angular
v11.0.5
で確認しました
作業環境
環境 | バージョン | 備考 |
---|---|---|
Angular CLI |
|
$ ng --version |
Angular |
|
同上 |
TypeScript | v4.0.2 | 同上 |
Node.js |
|
$ node --version |
npm |
|
$ npm --version |
ng version の結果
$ ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 11.0.5
Node: 12.18.3
OS: darwin x64
Angular: 11.0.5
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1100.5
@angular-devkit/build-angular 0.1100.5
@angular-devkit/core 11.0.5
@angular-devkit/schematics 11.0.5
@schematics/angular 11.0.5
@schematics/update 0.1100.5
rxjs 6.6.0
typescript 4.0.2
前提条件
- Angular CLI でプロジェクトを作成している
Angular CLI でサービスの雛形を作る
Angular CLI から次のコマンドで雛形を作ることができる。
サービス生成のコマンド
$ ng generate service service/common
create src/app/service/common.service.spec.ts (374 bytes)
create src/app/service/common.service.ts (112 bytes)
コンポーネント生成と同じく、 generate
は g
と省略することもできる。
それ以外のポイントとしては
-
ディレクトリ/サービス名
とすることでサービスを配置するディレクトリを生成した上でファイルが生成される- コンポーネントの場合は単純に
ng g component コンポーネント名
でディレクトリが生成されたが、サービスの場合はディレクトリを明示的に指定してやらなければいけない点に注意
- コンポーネントの場合は単純に
- サービスは
app.module.ts
に自動で登録されない- コンポーネントの場合は自動で登録されていたので、ここもコンポーネント-サービスとで異なる点として注意
といった項目があげられる。
*.ts ファイルをみる
生成したサービスをみると次のようになっている。
import { Injectable } from '@angular/core';
@Injectable()
export class CommonService {
constructor() { }
}
ポイントは
-
Injectable
がimport
されていること -
@Injectable
でクラスが修飾されていること
の 2点 で、これによって DI( Dependency Injection ) が行えることを宣言することになる。
サービスの利用
サービスを利用するには、アプリ全体でインスタンスを共有するために app.module.ts
で providers
に登録してやる必要がある。
と、その前に CommonService
を修正し、サービスとして DI された際に使用するプロパティを用意しておく。
サービスを修正する
import { Injectable } from '@angular/core';
@Injectable()
export class CommonService {
/**
* 本サービスを DI したコンポーネントで参照されるプロパティ
*
* @type {String}
* @memberof CommonService
*/
public commonProp: String = '';
/**
* コンストラクタ. CommonService のインスタンスを生成する
*
* @memberof CommonService
*/
constructor() {
this.commonProp = 'このプロパティは CommonService のもの';
}
}
ただプロパティを定義しただけの単純なコードだが、ポイントは
- DI された際に参照されるプロパティとして
commonProp
を定義 - コンストラクタで初期化
となる。
サービスを登録する
前述の通り、サービスの利用には
-
app.module.ts
でimport
~providers
に登録
する必要がある。以下、実際にコードをみていく。
// 省略
// サービスを登録するための import
import { CommonService } from './service/common.service';
@NgModule({
declarations: [
// 省略
],
imports: [
// 省略
],
// サービスを登録する
providers: [
CommonService
],
// 省略
})
export class AppModule { }
これで
-
CommonService
のインスタンスがアプリ全体で共有されるサービスとして登録された
ことになる。
あとは利用したいコンポーネントでサービスを DI してやれば良い。
サービスを DI する
app.module.ts
で登録したサービスを DI するには
- 使用したいコンポーネントで
import
してコンストラクタで引数にセット
することで実現できる。実際のコードは次の通り。
クラス
import { Component, OnInit } from '@angular/core';
// サービスを登録するための import
import { CommonService } from '../service/common.service';
@Component({
selector: 'app-sample1',
templateUrl: './sample1.component.html',
styleUrls: ['./sample1.component.css']
})
export class Sample1Component implements OnInit {
/**
* CommonService のプロパティの参照を取得するプロパティ
*
* @type {String}
* @memberof Sample1Component
*/
public serviceProp: String = '';
/**
* コンストラクタ. ServiceSample1Component のインスタンスを生成する
*
* @param {CommonService} commonService 共通サービス
* @memberof Sample1Component
*/
constructor(private commonService: CommonService) { }
/**
* ライフサイクルメソッド。コンポーネントの初期化で使用する
*
* @memberof Sample1Component
*/
ngOnInit() {
this.serviceProp = this.commonService.commonProp;
}
}
ポイントは次の 3点。
-
import
したサービスをコンストラクタの引数にセット - サービスで定義されたプロパティの値を取得するためのプロパティの定義
- ngOnInit でサービスから値を取得
これによって CommonService
で定義、セットされたプロパティの値を DI したコンポーネントで取得できる。
テンプレート
取得したサービスの値を表示するためのテンプレートは次の通り。
<p>
CommonService で設定されている値は「 {{this.serviceProp}} 」です。
</p>
こちらはクラスで定義したプロパティに対して片方向データバインドしただけの単純なもの。
実行結果
オレンジ枠で囲った部分に CommonService
でセットした文字列が表示されていることが確認できる。
まとめ
サービスを利用するにあたり、次の点を確認できた。
-
ng g service サービス名
でサービスを生成できる - ディレクトリを指定する場合は
ng g service ディレクトリ/サービス名
とすればよい- このときディレクトリがなければディレクトリを生成した上でサービスが生成される
- 生成されたサービスは
@Injectable
で修飾されている- これによって DI( Dependency Injection ) が行えることを宣言している
- サービスは( コンポーネントと異なり )生成しただけではアプリに登録されない
- サービスは
app.module.ts
で登録することでアプリ全体でインスタンスを共有することになる - サービスの利用にあたっては、利用するコンポーネント側で
import
し、コンストラクタの引数にセットする必要がある
補足
コンポーネントでサービスを DI する
なおサービスの DI は app.module.ts
だけではなく、任意のコンポーネントで行うこともできる。
実装方法は次の通り。
import { Component, OnInit } from '@angular/core';
// サービスを登録するための import
import { CommonService } from '../service/common.service';
@Component({
selector: 'app-sample1',
templateUrl: './sample1.component.html',
styleUrls: ['./sample1.component.css'],
providers: [
// サービスを登録する
CommonService
]
})
export class Sample1Component implements OnInit {
/**
* CommonService のプロパティの参照を取得するプロパティ
*
* @type {String}
* @memberof Sample1Component
*/
public serviceProp: String = '';
/**
* コンストラクタ. ServiceSample1Component のインスタンスを生成する
*
* @param {CommonService} commonService 共通サービス
* @memberof Sample1Component
*/
constructor(private commonService: CommonService) { }
/**
* ライフサイクルメソッド。コンポーネントの初期化で使用する
*
* @memberof Sample1Component
*/
ngOnInit() {
this.serviceProp = this.commonService.commonProp;
}
}
この場合、
-
app.module.ts
でサービスのimport
とproviders
への登録は不要
である。
またコンポーネントでサービスを DI した場合、
- そのサービスはアプリ全体での共有は行われない
- DI したコンポーネント、及びその子コンポーネントでのみ共有される
ので注意すること。
ソースコード
今回の記事で動作確認に使用したコードは ここ にアップしたので、ご参考までに。。。