Angular公式ドキュメントに沿ってAngular理解②

# はじめに

[Angular公式ドキュメントに沿ってAngular理解①](https://qiita.com/honda28/items/d36a6394c330fd292e86)で Angular の基本的な構造を理解した。引き続き、公式ドキュメントに沿って理解していく。

# Angular チュートリアル

[ナビゲーションの追加](https://angular.jp/start/start-routing)にしたがって、サンプルコードを元に修正・追加をしながら進めていく形式になっている。本記事では以下を行う。

- アドレスバーに URL を入力して、対応する商品ページに移動
- ページ上のリンクをクリックして、単一ページのアプリケーション内を移動
- ブラウザの戻るボタンと進むボタンをクリックして、ブラウザの履歴を直感的にナビゲート

## URL パスをコンポーネントに関連付ける

### 1. ルーティングの追加

商品詳細用の新しいコンポーネント ProductDetailsComponent を作成する。app.module.ts にて `path` と `component` を追加する。また公式ドキュメントには記載がないが、`declarations` にも `ProductDetailsComponent` を追加しておく。

```typescript:app.module.ts
@NgModule({
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent }
    ])
  ],
  declarations: [
    AppComponent,
    TopBarComponent,
    ProductListComponent,
    ProductAlertsComponent,
    ProductDetailsComponent
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
```

### 2. anchor に `routerLink` を追加

product.id をパラメータとして、商品名にリンクを貼る。[RouteLink](https://angular.jp/start/start-routing) ディレクティブは、パスを配列で受け取ることで動的にリンクを変更することができる。（パラメータも配列に含めれば渡すことができる。）

```html:product-list.component.html
<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'" [routerLink]="['/products', product.id]">
      {{ product.name }}
    </a>
  </h3>
...
```

上記修正により、商品名をクリックするとページ遷移することが確認できる。

## 商品詳細を見る

### 1. プロパティの定義

products の配列をインポートして、product プロパティを定義する。

```typescript:product-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Product, products } from '../products';

export class ProductDetailsComponent implements OnInit {
  product: Product|undefined;
  /* ... */
}
```

### 2. `@ActivatedRoute`

`Angular Router` を利用して products のデータとルート情報を組み合わせて、各商品の詳細を表示する。まず `@angular/router` から `ActivatedRoute` をインポートして、`constructor()` でインジェクションする。

```typescript:product-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Product, products } from '../products';

export class ProductDetailsComponent implements OnInit {
  product: Product|undefined;

  constructor(
    private route: ActivatedRoute,
  ) { }

}
```

サービスをインジェクションするとコンポーネントからサービスが見えるようになる。したがって、[ActivatedRoute](https://angular.jp/api/router/ActivatedRoute) をインジェクションしたことでコンポーネントは route から自身のルートに関する情報を容易に得ることができる。（サービスのインジェクションの嬉しさは、容易にいろんな機能をコンポーネント内で使用できることと理解している。インジェクション関連の理解は浅いので、間違っていたらぜひご指摘を。）

### 3. `ngOnInit()` メソッド

Angular にはコンポーネントの作成・更新・破棄といった LifeCycle に紐づくタイミングで実行できるメソッドが存在し、__`ngOnInit()` メソッドはコンポーネントの作成後に呼び出されるもの__である。`constructor()` と似たものに見えるが、__`constructor()` はコンポーネントの作成途中に呼び出されるもの__である。
ここでは route.snapshot.pramMap がもつ `get()` メソッドで productId を取得し、products 配列から `find()` 関数を使って対応する商品を取得している。ActivatedRoute のプロパティは [ActivatedRoute](https://angular.jp/api/router/ActivatedRoute) を参照。

```typescript:product-details.component.ts
ngOnInit() {
  // First get the product id from the current route.
  const routeParams = this.route.snapshot.paramMap;
  const productIdFromRoute = Number(routeParams.get('productId'));

  // Find the product that correspond with the id provided in route.
  this.product = products.find(product => product.id === productIdFromRoute);
}
```

ちなみに試しに `ngOnInit()` メソッド内の処理を `constructor()` で実行してみたところ、問題なく動作した。具体的な使い分けがパッと思い浮かばないので、ご存知の方は教えて下さい。

### 4. 商品詳細の表示

商品の存在有無を `*ngIf` で判断して、存在する場合には名前、価格、説明が表示されるようにテンプレートを更新する。

```html:product-details.component.html
<h2>Product Details</h2>

<div *ngIf="product">
  <h3>{{ product.name }}</h3>
  <h4>{{ product.price | currency }}</h4>
  <p>{{ product.description }}</p>

</div>
```

`<h4>{{ product.price | currency }}</h4>` は、`currency` パイプを通して数値を通貨文字列に変更しているとのこと。USD のためのものだからあんまり覚えておかなくてよさそう。[パイプ](https://angular.jp/guide/pipes)は使うことがありそうなので、覚えておこう。

# おわりに

ルーティングの設定を行った。リンクと対応するコンポーネントを設定し、anchor にリンクを貼るだけでよく、とても簡潔明瞭だった。引き続き、Angular の理解を深めていきたい。