【Angular】router-outlet で呼び出されたComponentのメソッドを利用する

## やりたいこと
`<router-outlet>`に表示されているComponentのメソッドを、templateに`<router-outlet>`を利用しているComponentから利用したい。

## 環境
* Angular CLI 8.1.2
* nodeJS 10.16.3
* npm 4.0.5

## 解決法
`RouterOutlet`の`@Output('activate')`を利用すれば、Componentが取得可能でした。

公式サイトの説明↓
> A router outlet will emit an activate event any time a new component is being instantiated, and a deactivate event when it is being destroyed.

`acrtivate`イベントはComponentがインスタンス化される度に呼び出されるようです。
このイベントで取得できる`$event`には呼び出されたComponentが格納されており、`$event`を`<router-outlet>`を保持しているComponentの保持することで、Componentにアクセスすることができます。
## 具体的な実装
以下、動作を確認したソースを記載します。

### ルート定義
app-routing.module.ts

```typescript
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { RoutingTestComponent } from "./routing-test/routing-test.component";
import { FirstChildComponent } from "./first-child/first-child.component";
import { SecondChildComponent } from "./second-child/second-child.component";

const routes: Routes = [
  {
    path: 'routing',
    component: RoutingTestComponent,
    //  子ルートをchildrenで定義
    children: [
      { path: 'first', component: FirstChildComponent},
      { path: 'second', component: SecondChildComponent}
    ]
  }
];

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

```

### templateで`<router-outlet>`を利用しているComponent
routing-test.component.ts

```typescript
import { Component, OnInit } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";

@Component({
  selector: "app-routing-test",
  template: `
    <p>routing-test</p>
    <button (click)="goFirstChild()">first child</button>
    <button (click)="goSecondChild()">second child</button>
    <button (click)="save()" [disabled]="componentRef == null">save</button>
    <!-- routesでchildrenとして定義したComponentは↓に表示される -->
    <router-outlet (activate)="onActivate($event)"></router-outlet>
  `
})
export class RoutingTestComponent implements OnInit {
  /**
   * router-outletにより呼び出されたComponentへの参照
   */
  private componentRef;

  constructor(private router: Router, private activatedRoute: ActivatedRoute) {}

  ngOnInit() {}

  /**
   * FirstChildComponentへページ遷移
   */
  goFirstChild() {
    this.router.navigate(["first"], { relativeTo: this.activatedRoute });
  }

  /**
   * SecondChildComponentへページ遷移
   */
  goSecondChild() {
    this.router.navigate(["second"], { relativeTo: this.activatedRoute });
  }

  /**
   * 参照したComponentのsaveメソッドを呼び出す
   */
  save() {
    this.componentRef.save();
  }

  /**
   * router-outletによる画面切り替え時に呼び出される処理
   */
  onActivate(event) {
    // eventを通じて呼び出されたComponentを取得できる
    this.componentRef = event;
  }
}
```

### `<router-outlet>`に呼び出される側のComponent
first-child.component.ts

```typescript
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-first-child',
  template: `<p>first child</p>`
})
export class FirstChildComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  save(){
    console.log("first");
  }
}
```

second-child.component.ts

```typescript
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-second-child',
  template: `<p>second child</p>`
})
export class SecondChildComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  save(){
    console.log("second");
  }
}
```

### 各Componentに対応しているメソッドが呼び出されているか確認
1. FirstChild
![first_child.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146452/9fca6999-2dc7-21b1-1212-772a3c2f93f6.jpeg)

2. SecondChild
![second_child.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146452/1fbe4dfd-2c89-4946-8fa7-283d694e9da7.jpeg)

各Componentでそれぞれ定義した`save()`メソッドが呼び出されていることが確認できました！

## 参考サイト
[Can you use @ViewChild() or similar with a router-outlet? How if so?](https://stackoverflow.com/questions/45587507/angular-how-to-get-component-instance-of-router-outlet)
[RouterOutlet](https://angular.io/api/router/RouterOutlet#description)