やりたいこと
<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に対応しているメソッドが呼び出されているか確認
各Componentでそれぞれ定義したsave()
メソッドが呼び出されていることが確認できました!
参考サイト
Can you use @ViewChild() or similar with a router-outlet? How if so?
RouterOutlet