LoginSignup
6

More than 3 years have passed since last update.

posted at

updated at

【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

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

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
What you can do with signing up
6