Angularチュートリアルをやってみて -3-
チュートリアルを一通りやってみたが、よく分からなかった。
理解を深めるために、やった内容を書き出してみる。
今回はサービスについて復習する。
サービス
そもそも「サービス」とはなんなのか。チュートリアルでは、下記のように説明されている。
サービスは、お互いを知らない クラスの間で情報を共有する最適な方法です。
Angularではコンポーネントでデータの取得や更新をすべきではないので、データの取得や更新を行う「サービス」を使うらしい。
サービスを作成してみる。
ng generate service message
作成された雛型はこうなった。
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MessageService { constructor() { } }
ここで、@Injectable
が大事そう。チュートリアルでは、下記のように説明されている。
クラスを依存関係注入システムに参加するものとしてマークします。
意味が分からないので、調べてみると下記のように説明されていた。
サービスクラスであることの条件は、@Injectableデコレーターで修飾されていることです。@Injectableデコレーターを付与することで、クラスをサービスとしてコンポーネントに引き渡せるようになります。
つまり、@Injectable
があれば「サービス」になると解釈することができる。@Injectable
にprovidedIn
があり、'root'
の場合は、ルートでのインスタンスとなる。
ボタン「メッセージ」で「msg1」、ボタン「メッセージ2」で「msg2」をテキストボックスに入力した文字列に追加する機能を作成する。
//message.service.ts import { Injectable} from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MessageService { private message: string = ""; public add(intext: string): void{ this.message = intext + "_msg1"; } public add2(intext: string): void{ this.message = intext + "_msg2"; } public get(): string{ return this.message } constructor() { } }
add()
により「msg1」を追加し、add2()
により「msg2」を追加する。get()
は表示のためにmessage
を返すメソッドとなっている。
呼び出すコンポーネントは次のように作成した。
//app.component.ts import { Component, OnInit } from '@angular/core'; import { MessageService } from './message.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ public text: string = ""; public outtext: string = ""; constructor(private mService: MessageService) { } ngOnInit(): void{ } public show(){ this.mService.add(this.text); this.outtext = this.mService.get(); } public show2(){ this.mService.add2(this.text); this.outtext = this.mService.get(); } }
<!--app.component.html--> <input type="text" [(ngModel)]="text" /> <br> <label>{{text}}</label> <br> <input type="button" (click)="show()" value="メッセージ" /><br> <input type="button" (click)="show2()" value="メッセージ2" /><br> <label>{{outtext}}</label>
HTMLでは2つのボタンを設定し、それぞれshow()
とshow2()
をクリック時に呼び出す。これで、ボタンを押すとテキストボックスの入力値に対して、文字列を追加する。
これを変更して、ボタンを押すたびに増えていくように変更する。
//message.service.ts import { Injectable} from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MessageService { private message: string = ""; public add(intext: string): void{ this.message = this.message + intext + "_msg1"; } public add2(intext: string): void{ this.message = this.message + intext + "_msg2"; } public get(): string{ return this.message } constructor() { } }
サービスの内容を変更した。サービスの変数に対して、テキストボックスの入力内容を追加していくようにした。
次に、このサービスを2つのコンポーネントから利用する。コードを以下のように変更した。
<!--app.component.html--> <app-a-component></app-a-component> <app-b-component></app-b-component>
//a-component.component.ts import { Component, OnInit } from '@angular/core'; import { MessageService } from '../message.service'; @Component({ selector: 'app-a-component', templateUrl: './a-component.component.html', styleUrls: ['./a-component.component.css'] }) export class AComponentComponent implements OnInit { constructor(private mService : MessageService) { } public text: string= ""; public outtext: string=""; ngOnInit() { } public show(){ this.mService.add(this.text); this.outtext = this.mService.get(); } public show2(){ this.mService.add2(this.text); this.outtext = this.mService.get(); } }
<p> a-component works! </p> <input type="text" [(ngModel)]="text" /> <br> <label>{{text}}</label> <br> <input type="button" (click)="show()" value="メッセージ" /><br> <input type="button" (click)="show2()" value="メッセージ2" /><br> <label>{{outtext}}</label>
//b-component.component.ts import { Component, OnInit } from '@angular/core'; import { MessageService } from '../message.service'; @Component({ selector: 'app-b-component', templateUrl: './b-component.component.html', styleUrls: ['./b-component.component.css'] }) export class BComponentComponent implements OnInit { constructor(private mService : MessageService) { } public text: string= ""; public outtext: string=""; ngOnInit() { } public show(){ this.mService.add(this.text); this.outtext = this.mService.get(); } public show2(){ this.mService.add2(this.text); this.outtext = this.mService.get(); } }
<p> b-component works! </p> <input type="text" [(ngModel)]="text" /> <br> <label>{{text}}</label> <br> <input type="button" (click)="show()" value="メッセージ" /><br> <input type="button" (click)="show2()" value="メッセージ2" /><br> <label>{{outtext}}</label>
aとbの2つのコンポーネントを用意し、それぞれにボタンを配置した。実行すると、出力される文字列はaとbで共有されていることが分かる。これは、サービスの宣言部分で、
@Injectable({ providedIn: 'root' })
上記のように宣言しているためである。この宣言では、'root'
つまり、最上位での宣言を行っているため、aとbのそれぞれでサービスを作成していることにはなっていない。
これをaとbで独立したサービスとするためには、次のように宣言する。
//a-component.component.ts @Component({ selector: 'app-a-component', templateUrl: './a-component.component.html', styleUrls: ['./a-component.component.css'], providers: [MessageService] })
//b-component.component.ts @Component({ selector: 'app-b-component', templateUrl: './b-component.component.html', styleUrls: ['./b-component.component.css'], providers: [MessageService] })
これにより、別々の独立したサービスとすることができる。