From 70e9f4bf93c1ab1eb840d6a6c8bde4c15a5c0b20 Mon Sep 17 00:00:00 2001 From: MasanobuAkiba Date: Mon, 20 Nov 2017 22:32:44 +0900 Subject: [PATCH] translate: tutorial/toh-pt4.md --- aio-ja/content/tutorial/toh-pt4.md | 333 ++++++++++++++--------------- 1 file changed, 156 insertions(+), 177 deletions(-) diff --git a/aio-ja/content/tutorial/toh-pt4.md b/aio-ja/content/tutorial/toh-pt4.md index fe7a818f8a..976b7917ef 100644 --- a/aio-ja/content/tutorial/toh-pt4.md +++ b/aio-ja/content/tutorial/toh-pt4.md @@ -1,232 +1,218 @@ -# Services +# サービス -The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data. +Tour of Heroes の中で扱っている `HeroesComponent` は、今のところ仮のデータを取得して表示している状態です。 -After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view. -It will also be easier to unit-test with a mock services. +このチュートリアルのリファクタリング後には、`HeroesComponent` は小さくなりビューをサポートすることに専念します。 +これはモックサービスを使用して、ユニットテストをより簡潔にすることにもつながります。 -## Why services +## なぜサービスが必要なのか? -Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data. -They should focus on presenting data and delegate data access to a service. +コンポーネント内では直接データの取得や保存を行うべきではありません。 +もちろん、故意に仮のデータを渡してもいけません。 +コンポーネントはデータの受け渡しに集中し、その他の処理はサービスクラスへ委譲するべきです。 -In this tutorial, you'll create a `HeroService` that all application classes can use to get heroes. -Instead of creating that service with `new`, -you'll rely on Angular [*dependency injection*](guide/dependency-injection) -to inject it into the `HeroesComponent` constructor. +このチュートリアルでは、アプリケーション全体でヒーローを取得できる `HeroService` を作成します。 +そのサービスは `new` で生成するのではなく、Angular による [*依存性の注入*](guide/dependency-injection) で、 `HeroesComponent` コンストラクタに注入します。 -Services are a great way to share information among classes that _don't know each other_. -You'll create a `MessageService` and inject it in two places: +サービスは、_お互いを知らない_ クラスの間で情報を共有する最適な方法です。 +このチュートリアル後半でも `MessageService` を作成し、次の2クラスに注入します。 -1. in `HeroService` which uses the service to send a message. -2. in `MessagesComponent` which displays that message. +1. `HeroService`: メッセージを送信するため +2. `MessagesComponent`: そのメッセージを表示するため +## _HeroService_ の作成 -## Create the _HeroService_ - -Using the Angular CLI, create a service called `hero`. +Angular CLI を使用して `HeroService` を作成しましょう。 ng generate service hero -The command generates skeleton `HeroService` class in `src/app.hero.service.ts` -The `HeroService` class should look like the below. +このコマンドは `HeroService` のスケルトンファイルを `src/app.hero.service.ts` に生成します。`HeroService` クラスは次のようになっているはずです。 -### _@Injectable()_ services +### _@Injectable()_ サービス -Notice that the new service imports the Angular `Injectable` symbol and annotates -the class with the `@Injectable()` decorator. +生成されたファイル内で Angular の Injectable シンボルがインポートされ、`@Injectable()` デコレータとしてクラスを注釈していることに注目してください。 -The `@Injectable()` decorator tells Angular that this service _might_ itself -have injected dependencies. -It doesn't have dependencies now but [it will soon](#inject-message-service}. -Whether it does or it doesn't, it's good practice to keep the decorator. +`@Injectable()` デコレータは、このサービス自体が依存関係を注入している可能性があることを示しています。 +現時点で依存関係があるわけではありませんが、[この後すぐに設定します](#inject-message-service)。 +依存関係の有無にかかわらず、このデコレータを付けておくとよいでしょう。
-The Angular [style guidelines](guide/styleguide#style-07-04) strongly recommend keeping it -and the linter enforces this rule. +Angular の [スタイルガイド](guide/styleguide#style-07-04) ではそれを強くおすすめしています。 +また、リンターはこのルールを基準として指摘を行います。
-### Get hero data +### ヒーローデータの取得 -The `HeroService` could get hero data from anywhere—a web service, local storage, or a mock data source. +`HeroService` は様々な場所からヒーローデータを取得する可能性があります。— 外部Webサービス、ローカルストレージ、またはモックデータかもしれません。 -Removing data access from components means you can change your mind about the implementation anytime, without touching any components. -They don't know how the service works. +コンポーネントからデータ取得ロジックを切り離すということは、そういったサービス側の事情にとらわれず、いつでも実装方針の変更ができることを意味しています。 +コンポーネント側は、サービスがどのように動いていようと関係ありません。 -The implementation in _this_ tutorial will continue to deliver _mock heroes_. +この章の実装では、引き続き _モックヒーロー_ を使用します。 -Import the `Hero` and `HEROES`. +`Hero` および `HEROES` をインポートします。 -Add a `getHeroes` method to return the _mock heroes_. +`getHeroes` メソッドを追加し、_モックヒーロー_ を返します。 {@a provide} -## Provide the `HeroService` +## `HeroService` の提供 -You must _provide_ the `HeroService` in the _dependency injection system_ -before Angular can _inject_ it into the `HeroesComponent`, -as you will do [below](#inject). +Angularが `HeroesComponent` へ注入する([次に](#inject)行います)よりも前に、 _依存性の注入システム_ に `HeroService` を _提供_ する必要があります。 -There are several ways to provide_ the `HeroService`: -in the `HeroesComponent`, in the `AppComponent`, in the `AppModule`. -Each option has pros and cons. +`HeroService` を _提供_ する方法はいくつか存在し、`HeroesComponent`、`AppComponent` または `AppModule` で行うことができます。 +また、それぞれの方法にはメリット・デメリットが存在します。 -This tutorial chooses to provide it in the `AppModule`. +このチュートリアルでは、 `AppModule` 内で提供を行います。 -That's such a popular choice that you could have told the CLI to provide it there automatically -by appending `--module=app`. +`--module=app` オプションを付与して提供を自動化するようにCLIに伝えるのが一般的な選択です。 ng generate service hero --module=app -Since you did not, you'll have to provide it yourself. +そのオプションを利用しない場合は、手動で提供する必要があります。 -Open the `AppModule` class, import the `HeroService`, and add it to the `@NgModule.providers` array. +`AppModule` クラスを開いた後、インポートした `HeroService` を `@NgModule.providers` に追加します。 -The `providers` array tells Angular to create a single, shared instance of `HeroService` -and inject into any class that asks for it. +Angular は `providers` からひとつの `HeroService` インスタンスを生成し、それを利用しているクラスへ注入します。 -The `HeroService` is now ready to plug into the `HeroesComponent`. +これにより、 `HeroService` は `HeroesComponent` で利用できる状態になりました。
- Learn more about _providers_ in the [NgModules](guide/ngmodule#providers) guide. + +_providers_ についてより詳しく知りたい方は [NgModules](guide/ngmodule#providers) を参照してください。 +
-## Update `HeroesComponent` -Open the `HeroesComponent` class file. +## `HeroesComponent` の更新 -Delete the `HEROES` import as you won't need that anymore. -Import the `HeroService` instead. +`HeroesComponent` クラスを開いてください。 + +不要となった `HEROES` を削除する代わりに、 `HeroService` をインポートしましょう。 -Replace the the definition of the `heroes` property with a simple declaration. +`heroes` プロパティの定義を、単純な宣言に置き換えます。 {@a inject} -### Inject the `HeroService` +### `HeroService` の注入 -Add a private `heroService` parameter of type `HeroService` to the constructor. +`HeroService` 型のプライベートプロパティである `heroService` をコンストラクタに追加しましょう。 -The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site. +このパラメータはプライベートな `heroService` プロパティとして定義されると同時に、 `HeroService` を注入すべき場所として認識されます。 -When Angular creates a `HeroesComponent`, the [Dependency Injection](guide/dependency-injection) system -sets the `heroService` parameter to the singleton instance of `HeroService`. +Angular が `HeroesComponent` を生成する際、[依存性の注入](guide/dependency-injection) システムは `heroService` パラメータを `HeroService` のシングルトンインスタンスとして設定します。 -### Add _getHeroes()_ +### _getHeroes()_ の追加 -Create a function to retrieve the heroes from the service. +サービスからヒーローデータを取得するための関数を作成しましょう。 {@a oninit} -### Call it in `ngOnInit` +### `ngOnInit` での呼び出し -While you could call `getHeroes()` in the constructor, that's not the best practice. +`getHeroes()` はコンストラクタでも呼び出すことはできますが、これは最適な方法ではありません。 -Reserve the constructor for simple initialization such as wiring constructor parameters to properties. -The constructor shouldn't _do anything_. -It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would. +コンストラクタではプロパティ定義などの簡単な初期化のみを行い、それ以外は _何もするべきではありません_ 。 +もちろん、_実際の_ データ取得サービスが行うであろう、サーバーへのHTTPリクエストを行う関数は呼び出すべきではありません。 -Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) and -let Angular call `ngOnInit` at an appropriate time _after_ constructing a `HeroesComponent` instance. +`getHeroes()` はコンストラクタではなく、 [*ngOnInit ライフサイクルフック*](guide/lifecycle-hooks) 内で呼び出しましょう。 +この `ngOnInit` は、 Angular が `HeroesComponent` インスタンスを生成した後、適切なタイミングで呼び出されます。 -### See it run +### 実行の確認 + +ブラウザの更新後、アプリケーションは以前と同じように実行されるはずです。 +ヒーローリストが表示され、ヒーロー名をクリックすると詳細が表示されるでしょう。 -After the browser refreshes, the app should run as before, -showing a list of heroes and a hero detail view when you click on a hero name. +## Observable データ -## Observable data +`HeroService.getHeroes()` は同期的なメソッドであり、これは `HeroService` が即座にヒーローデータを取得できることを示しています。 -The `HeroService.getHeroes()` method has a _synchronous signature_, -which implies that the `HeroService` can fetch heroes synchronously. -The `HeroesComponent` consumes the `getHeroes()` result -as if heroes could be fetched synchronously. +また `HeroesComponent` は、`getHeroes()` の返り値がまるで同期的に取得できるかのように扱っています。 -This will not work in a real app. -You're getting away with it now because the service currently returns _mock heroes_. -But soon the app will fetch heroes from a remote server, -which is an inherently _asynchronous_ operation. +しかしこれは、実際のアプリケーションでは機能しません。 +現在のサービスはモックヒーローを返しているのでこれを免れていますが、 +リモートサーバーからヒーローデータを取得するにあたり、この処理は _非同期_ ということに気づくでしょう。 -The `HeroService` must wait for the server to respond, -`getHeroes()` cannot return immediately with hero data, -and the browser will not block while the service waits. +`HeroService` はサーバーのレスポンスを待たなければならず、`getHeroes()` は即座にヒーローデータを返すことができません。 +そしてそのサービスが待機している間、ブラウザはブロックされないでしょう。 -`HeroService.getHeroes()` must have an _asynchronous signature_ of some kind. +`HeroService.getHeroes()` は何らかの非同期処理を実装する必要があります。 -It can take a callback. It could return a `Promise`. It could return an `Observable`. +それには、コールバック関数、`Promise`、または `Observable` を使用することができるでしょう。 -In this tutorial, `HeroService.getHeroes()` will return an `Observable` -in part because it will eventually use the Angular `HttpClient.get` method to fetch the heroes -and [`HttpClient.get()` returns an `Observable`](guide/http). +この章では、`HeroService.getHeroes()` は `Observable` を返します。 +なぜなら、後にヒーローデータの取得で利用する Angular の [`HttpClient.get()`](guide/http) メソッドが `Observable` を返すからです。 ### Observable _HeroService_ -`Observable` is one of the key classes in the [RxJS library](http://reactivex.io/rxjs/). +`Observable` は [RxJS ライブラリ](http://reactivex.io/rxjs/) で重要なクラスのひとつです。 -In a [later tutorial on HTTP](tutorial/toh-pt6), you'll learn that Angular's `HttpClient` methods return RxJS `Observable`s. -In this tutorial, you'll simulate getting data from the server with the RxJS `of()` function. +[HTTP に関する後の章](tutorial/toh-pt6), でも Angular の `HttpClient` メソッドが `Observable` を返すことに触れるでしょう。 +この章ではRxJSの `of()` 関数を使ってサーバーからのデータの取得をシミュレートします。 -Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS. +`HeroService` を開き、`Observable` および `of` を `RxJS` からインポートします。 - -Replace the `getHeroes` method with this one. +`getHeroes` メソッドを `Observable` 形式で書き直しましょう。 -`of(HEROES)` returns an `Observable` that emits _a single value_, the array of mock heroes. +`of(HEROES)` は _ひとつの値_、すなわちモックヒーローの配列を出力する `Observable` を返します。
-In the [HTTP tutorial](tutorial/toh-pt6), you'll call `HttpClient.get()` which also returns an `Observable` that emits _a single value_, an array of heroes from the body of the HTTP response. +[HTTP のチュートリアル](tutorial/toh-pt6) では、_ひとつの値_、すなわちHTTPレスポンスボディ由来のヒーローの配列を出力する `Observable` を同じように返す `HttpClient.get()` を呼び出します。
-### Subscribe in _HeroesComponent_ +### _HeroesComponent_ での Subscribe -The `HeroService.getHeroes` method used to return a `Hero[]`. -Now it returns an `Observable`. +`HeroService.getHeroes` メソッドは `Hero[]` を返していましたが、 +現在の返り値は `Observable` です。 -You'll have to adjust to that difference in `HeroesComponent`. +そのため、これらの違いを修正する必要があるでしょう。 -Find the `getHeroes` method and replace it with the following code -(shown side-by-side with the previous version for comparison) +`getHeroes` を開き、下記コードに変更しましょう。 +(比較のために以前のバージョンと横に並べられています) @@ -240,81 +226,78 @@ Find the `getHeroes` method and replace it with the following code -`Observable.subscribe()` is the critical difference. +`Observable.subscribe()` はとても重要な違いです。 -The previous version assigns an array of heroes to the component's `heroes` property. -The assignment occurs _synchronously_, as if the server could return heroes instantly -or the browser could freeze the UI while it waited for the server's response. +修正前のコードでは、`heroes` プロパティにヒーローリストを代入していました。 +その代入は、まるでサーバーが即座に値を返すか、レスポンスを待機する間UIのレンダリングを中止したかのように _同期的_ です。 -That _won't work_ when the `HeroService` is actually making requests of a remote server. +`HeroService` が実際にサーバーへのレクエストを行う場合、修正前のコードは動作しません。 -The new version waits for the `Observable` to emit the array of heroes— -which could happen now or several minutes from now. -Then `subscribe` passes the emitted array to the callback, -which sets the component's `heroes` property. +新しいバージョンでは、`Observable` がヒーローの配列を出力するのを待っています。— +これは現在あるいは数分後に起こる可能性があります。 +そのとき、subscribeは、出力された配列をコールバックに渡し、コンポーネントの `heroes` プロパティを設定します。 -This asynchronous approach _will work_ when -the `HeroService` requests heroes from the server. +この非同期的手法は、`HeroService` がサーバーからヒーローを取得する際、正常に動作します。 -## Show messages +## メッセージの表示 -In this section you will +この節では次のことを行います。 -* add a `MessagesComponent` that displays app messages at the bottom of the screen. -* create an injectable, app-wide `MessageService` for sending messages to be displayed -* inject `MessageService` into the `HeroService` -* display a message when `HeroService` fetches heroes successfully. +* メッセージを表示するための `MessagesComponent` を画面下部に追加する +* 表示するメッセージを送信するために、アプリケーション全体で注入可能な `MessageService` を作成する +* `HeroService` に `MessageService` を注入する +* `HeroService` のデータ取得成功時にメッセージを表示する -### Create _MessagesComponent_ +### _MessagesComponent_ の作成 -Use the CLI to create the `MessagesComponent`. +Angular CLI を使い `MessagesComponent` を作成しましょう。 ng generate component messages -The CLI creates the component files in the `src/app/messages` folder and declare `MessagesComponent` in `AppModule`. +Angular CLI は `src/app/messages` 配下にコンポーネントファイル群を生成し、`AppModule` 内に `MessagesComponent` を宣言します。 -Modify the `AppComponent` template to display the generated `MessagesComponent` +作成した `MessagesComponent` を表示するために、`AppComponent` のテンプレートを修正しましょう。 -You should see the default paragraph from `MessagesComponent` at the bottom of the page. +`MessagesComponent` のデフォルトテキストが、ページ最下部に配置されていることを確認してください。 -### Create the _MessageService_ +### _MessageService_ の作成 -Use the CLI to create the `MessageService` in `src/app`. -The `--module=app` option tells the CLI to [_provide_ this service](#provide) in the `AppModule`, +Angular CLI を使い、`src/app` 配下に `MessageService` を作成します。 +この際 `--module=app` オプションを利用し、`AppModule` へ [このサービスを_提供_](#provide) するように伝えましょう。 ng generate service message --module=app -Open `MessageService` and replace its contents with the following. +`MessageService` を開き、次のコードへ修正してください。 -The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache. +このサービスは `messages` および `add()`、`clear()` メソッドを他のクラスから利用できるように公開しています。 +また、`add()` メソッドは新たなメッセージを `messages` へ追加し、`clear()` メソッドは `messages` の値を初期化します。 {@a inject-message-service} -### Inject it into the `HeroService` +### `HeroService` への注入 -Re-open the `HeroService` and import the `MessageService`. +再び `HeroService` を開き、`MessageService` をインポートしましょう。 -Modify the constructor with a parameter that declares a private `messageService` property. -Angular will inject the singleton `MessageService` into that property -when it creates the `HeroService`. +プライベートな `messageService` プロパティを宣言するパラメータを使用してコンストラクタを変更します。 +Angular は `HeroService` を生成する際、そのプロパティへシングルトンな `MessageService` を注入します。 @@ -322,78 +305,75 @@ when it creates the `HeroService`.
-This is a typical "*service-in-service*" scenario: -you inject the `MessageService` into the `HeroService` which is injected into the `HeroesComponent`. +これは典型的な "*サービス内でサービスを利用する*" 例です。 +`HeroesComponent` に注入されている `HeroService` には、`MessageService` が注入されています。
-### Send a message from `HeroService` +### `HeroService` からメッセージを送る -Modify the `getHeroes` method to send a message when the heroes are fetched. +ヒーローが取得されたときにメッセージを送信するように `getHeroes` メソッドを変更します。 -### Display the message from `HeroService` +### `HeroService` からのメッセージを表示する -The `MessagesComponent` should display all messages, -including the message sent by the `HeroService` when it fetches heroes. +`MessagesComponent` は `HeroService` がヒーローを取得した際に送信するメッセージを含め、全てのメッセージを表示しなければなりません。 -Open `MessagesComponent` and import the `MessageService`. +`MessagesComponent` を開き、`MessageService` をインポートしてください。 -Modify the constructor with a parameter that declares a **public** `messageService` property. -Angular will inject the singleton `MessageService` into that property -when it creates the `HeroService`. +コンストラクタに **パブリック** な `messageService` プロパティを宣言しましょう。 +Angular は `HeroService` を作成する際、シングルトンな `MessageService` インスタンスをそのプロパティへ注入します。 -The `messageService` property **must be public** because you're about to bind to it in the template. +今回、`messageService` はテンプレート内でバインドして使用します。 +そのため、`messageService` は **パブリックである必要があります**。
-Angular only binds to _public_ component properties. +Angular はコンポーネント内の _パブリック_ なプロパティのみをバインドします
-### Bind to the _MessageService_ +### _MessageService_ へバインドする -Replace the CLI-generated `MessagesComponent` template with the following. +Angular CLI によって生成された `MessagesComponent` のテンプレートを下記コードへ置き換えましょう。 -This template binds directly to the component's `messageService`. - -* The `*ngIf` only displays the messages area if there are messages to show. +このテンプレートは、コンポーネント内の `messageService` と直接紐付きます。 +* `*ngIf` は、表示するメッセージが存在する場合のみメッセージエリアを表示します -* An `*ngFor` presents the list of messages in repeated `
` elements. +* `*ngFor` は、`
` 要素をくり返してメッセージリストを表示します +* Angular の [イベントバインディング](guide/template-syntax#event-binding) は、ボタンのクリックイベントと `MessageService.clear()` を紐付けます -* An Angular [event binding](guide/template-syntax#event-binding) binds the button's click event -to `MessageService.clear()`. +["最終的なコードレビュー"](#final-code-review) タブ内に記載されている `messages.component.css` をコンポーネントのスタイルに追加すると、このメッセージUIの外観はより良いものになるでしょう。 -The messages will look better when you add the private CSS styles to `messages.component.css` -as listed in one of the ["final code review"](#final-code-review) tabs below. +ブラウザの更新後、ページにはヒーローの一覧が表示されます。 +ページを下へスクロールすると、メッセージエリア内に `HeroService` からのメッセージを確認できます。 +また、"クリア" ボタンをクリックすると、メッセージ領域はなくなります。 -The browser refreshes and the page displays the list of heroes. -Scroll to the bottom to see the message from the `HeroService` in the message area. -Click the "clear" button and the message area disappears. {@a final-code-review} -## Final code review +## 最終的なコードレビュー -Here are the code files discussed on this page and your app should look like this . +このページで解説したコードを以下に記載します。 +また、アプリケーションの見た目はリンク先のようになっているはずです。 . @@ -427,15 +407,14 @@ Here are the code files discussed on this page and your app should look like thi -## Summary - -* You refactored data access to the `HeroService` class. -* You _provided_ the `HeroService` in the root `AppModule` so that it can be injected anywhere. -* You used [Angular Dependency Injection](guide/dependency-injection) to inject it into a component. -* You gave the `HeroService` _get data_ method an asynchronous signature. -* You discovered `Observable` and the RxJS _Observable_ library. -* You used RxJS `of()` to return an _Observable_ of mock heroes (`Observable`). -* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor. -* You created a `MessageService` for loosely-coupled communication between classes. -* The `HeroService` injected into a component is created with another injected service, - `MessageService`. +## まとめ + +* `HeroService` クラスのデータ利用方法を修正しました +* ルートモジュールである `AppModule` に `HeroService` を提供することで、それをどこへでも注入できるようにしました +* [Angular の依存性の注入](guide/dependency-injection) を使用して、それをコンポーネントに注入しました +* `HeroService` の _データ取得_ メソッドを非同期化しました +* `Observable` および、それを扱うために利用する RxJS ライブラリについて学びました +* モックヒーローを _Observable_ (`Observable`) 型で返すために、RxJS の `of()` を使用しました +* コンポーネントのコンストラクタ内ではなく、`ngOnInit` ライフサイクルフックで `HeroService` メソッドを呼び出しました +* クラス間で疎結合な情報伝達を行うため、 `MessageService` を作成しました +* コンポーネントに注入された `HeroService` は、もうひとつのサービスである `MessageService` とともに作成されます