LoginSignup
8
6

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-09-18

やりたいこと

<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

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

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

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

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

  2. SecondChild
    second_child.jpg

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

参考サイト

Can you use @ViewChild() or similar with a router-outlet? How if so?
RouterOutlet

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6