Angularの画面遷移について

Angularの画面遷移について説明しようと思います。
画面遷移とは言えどもAngularはコンポーネントベースのもので、URLの切り替わり=ページの切り替わりではなく、コンポーネントの切り替わりというものになります。

## 目次
* プロジェクトの作成
* ルート設定
* RouterLinkによる方法
* RouterのnavigateByUrlによる方法
* リンクを階層構造にする


## プロジェクトの作成

```terminal:terminal
% ng new app-routing --routing
```

app-routingはプロジェクト名 --routingはプロジェクトでルーティングを使用する場合につけるオプションです。

作成後

```
app
 |- app-routing.module.ts  ←ルーティングを司るモジュール
 |- app.component.css
 |- app.component.html
 |- app.component.spec.ts
 |- app.component.ts
 |- app.module.ts          ←機能を司るモジュール
```
これらがデフォルトで作成されます。

## ルート設定
app.routing.moduleを編集します。

```typescript:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [];　

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```
routing.moduleのデフォルトの状態です。
`import { Routes, RouterModule } from '@angular/router';`でroute機能をimportしています

```typescript:routing.module.ts
const routes: Routes = [
  { path: '',component: hogeComponent, children: []}
];
```
上記のroutesの配列内に画面遷移の情報を入れていきます。

pathでパスの指定を行い、componentでそのパスを打ち込んだときに表示するcomponentを指定します。
childrenは階層構造の際に今のパスの次にパスを記述して、componentを切り替えたい、追加したい時に使用します。
基本の配列(routing.module.ts)の場合では起動した際にhogeComponentを表示させるという意味合いになります。childrenは指定がないので階層構造はなにもありません。

app.moduleでrouting.moduleのインポート

```typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';  //デフォルトでimportされている
import { AppComponent } from './app.component';
import { Hoge1Component } from './hoge1/hoge1.component';
import { Hoge2Component } from './hoge2/hoge2.component';

@NgModule({
  declarations: [
    AppComponent,
    Hoge1Component,
    Hoge2Component
  ],
  imports: [
    BrowserModule,
    AppRoutingModule  //デフォルトでimportされている
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```
コンポーネントのview

```html:app.component.html
<router-outlet></router-outlet>
```
`<router-outlet></router-outlet>`とあることで、pathのコンポーネントがここに表示されるようになります。
実際にやってみましょう。
先程の`app-routing.module`の配列を下記のように変更してください

```typescript:app-ruting.module.ts
const routes: Routes = [
  {path: 'hoge1', component: Hoge1Component},
  {path: 'hoge2', component: Hoge2Component}
];
```

localhost4200
![空白.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/8cc4c46e-295e-a7af-a6bd-448967b9f14a.png)

urlに/hoge1を追加した場合
![hoge1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/1e97caee-72b6-4bab-ef19-28d42e358a0a.png)

urlに/hoge2と追加した場合
![hoge2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/f1294186-1f59-591f-4034-790fca886453.png)

`これはタイトルです`はapp.componentの中身でその下に`hoge1.component`と`hoge2.component`が来るという形になります。下の画像でhoge1.componentとなっているところが`<router-outlet>`となっていて、URLが切り替わるごとにここが変わります。
![component.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/aa4b7764-f5bb-6243-7185-e2ce0cd6cbe1.png)

## リンクの挿入
今はURLを書き換えることでコンポーネントを切り替えるようにしていましたが、基本的にはリンクをクリックしてからのコンポーネント切り替えになりますので、それについて説明していきます。

切り替えの方法としては、HTMLに記述する方法(routerLink)とTypeScriptに記述していく方法(controller)があります

### RouterLinkによる方法
こちらはHTMLにリンクを記述する形になります。通常のHTMLとは異なった記述になります。

```html:app.component.html
<a routerLink="/hoge1">hoge1</a>
<a routerLink="/hoge2">hoge2</a>
<router-outlet></router-outlet>
```
hoge1用とhoge2用のリンクを作成します。
![appLink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/7b4cd59e-f185-432f-5053-4c339d6d2702.png)

![hoge1Link.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/59f0041a-8db1-c1c7-afbe-fc8732a7d33f.png)

![hoge2LInk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/abe513a1-0014-d394-2dcf-f59bf89d48a3.png)

URLによってコンポーネントが遷移することを確認できました。

### TypeScriptによる方法

HTMLのリンクをボタンにして表現する場合はTypeScriptに記述してやるのがいいです。
app.component.htmlのhoge2をボタンにしてみます

```html:app.component.html
<a routerLink="/hoge1">hoge1</a>
<button (click)="toHoge()">hoge2</button>
<router-outlet></router-outlet>
```
HTMLに記述されたメソッドの処理をTypeScriptに記述します。


```typescript:app.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router'; //←画面遷移ができるようRouterをインポートする

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'route-app';

  constructor (private router: Router) {

  }
  //クリックした時にURLに飛べるメソッドを作成  
  toHoge2(): void{
    this.router.navigateByUrl('/hoge2');  //navigateByUrlはRouterクラスのメソッド
  }
}
```
![hogeButton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/fe8cb5d9-0f18-16d1-0303-61baf1f78a6d.png)
hoge2がボタンに切り替わり、押すとURLとコンポーネントが切り替わります。

これらの切り替わりは全て一つのページ内で行われています。

## リンクを階層構造にする
今はapp.componentの下にhoge1とhoge2があります。
hoge1をクリックするとhoge3というリンクが表示されるようにします。
hoge1のリンクをクリックするとhoge3のコンポーネントに切り替わるため、app-routing.moduleのhoge1の下層にリンクを作成します

```typescript:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Hoge1Component } from './hoge1/hoge1.component';
import { Hoge2Component } from './hoge2/hoge2.component';
import { Hoge3Component } from './hoge3/hoge3.component';  //hoge3.compnent作成時に自動追加

const routes: Routes = [
  {
    path: 'hoge1',
    component: Hoge1Component,
    //ここから
    children: [                                 
      {path:'hoge3', component: Hoge3Component}  //子要素を作る。
    ]
    //ここまでを追加
  },
  {path: 'hoge2', component: Hoge2Component}     //子要素と見た目同じ
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

```html:hoge1.component.html
<div>
  <a routerLink="/hoge1/hoge3">hoge3</a>
</div>
```
ブラウザは下記のようになりましたが、hoge3のコンポーネントが見つかりません。(なおhoge3のリンクはhoge1のコンポーネントです)
![hoge3Link.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/8f50c56e-9ef3-1715-f455-3a2cf76d3153.png)

上のhoge1.component.htmlで`<router-outlet>`を記述していないからです。URLを変更しても、コンポーネントは表示されませんので追加しましょう。

```html:hoge1.component.html
<div>
  <a routerLink="/hoge1/hoge3">hoge3</a>
</div>
<router-outlet></router-outlet>
```
![hoge3Work.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665867/0b4ac417-b53b-b308-6063-49b4669ad71c.png)
hoge3のコンポーネントが表示されるようになりました。

## まとめ
コンポーネント切り替えを行うには
`routing.module`
pathの指定とそのパスではどのコンポーネントを扱うかという指定を行う

`html`
aタグでリンク先のpathを指定
buttonタグではTypeScriptでRouterクラスからURLへ飛ぶ処理を記述する

RoutingにはLazyLoadingという遅延ロードと呼ばれるものがあるので、その説明もおこないます。
失礼します。