親コンポーネントの状態を子コンポーネントの状態によって変更したいという時ってよくあると思います。
直接HTMLに子のセレクタを記載している場合なら、 @ViewChild
とか @ViewChildren
で取得してその中身を見れば良いですよね(その行為が良いかはともかく)。
でも、 router-outlet
の場合ってどうしていますか?
実は、 activate
Output()
で簡単に取得できるので、便利です。
例えば、子コンポーネントの状態によってタイトルを変えたいとしましょう(タイトルを変える場合にこの方法を使うのは微妙だと思いますが、わかりやすいので)
parent.component.ts
@Component({
selector: 'app-parent',
template: `<div><h1>{{ title }}</h1><router-outlet></router-outlet></div>`,
})
export class ParentComponent {
title: string;
nameToTitle = {
ONE: '1つ目',
TWO: '2つ目',
};
}
child1.component.ts
@Component({
selector: 'app-child1',
template: `<div>Child ONE!!</div>`
})
export ChildComponent {
name = 'ONE';
}
child2.component.ts
@Component({
selector: 'app-child2',
template: `<div>Child TWO!!</div>`
})
export ChildComponent {
name = 'TWO';
}
上記のコンポーネントが、routerにより、 child1
, child2
と変更されると想定します。
この場合、親コンポーネントを少し変更して下記のようにできます。
parent.component.ts
@Component({
selector: 'app-parent',
template: `<div><h1>{{ title }}</h1><router-outlet (activate)="onActivate($event)"></router-outlet></div>`, // <= activate を追加
})
export class ParentComponent {
title: string;
nameToTitle = {
ONE: '1つ目',
TWO: '2つ目',
};
onActivate(componentRef: any): void { // <= 追加
this.title = this.nameToTitle[componentRef.name];
}
}
これで簡単に router-outlet
の状態を参照して親コンポーネントの値を変更できます。
他のやり方としては、子コンポーネントから親コンポーネントをサービス経由で変更する、などの方法があります(こっちが一般的)。
でも全部のComponentでやるのは面倒なのでこういうやり方でも良いときはあるかなと(継承すればDRYにもできますが、時と場合によります)