← 解説「host — 自分自身の要素へバインドする」に戻る
サンプルコードで身につける: host — 自分自身の要素へバインドする
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1選択状態をホスト要素のクラスに反映する
host の '[class.selected]' でホスト要素にクラスを条件付きで付ける、いちばん基本の形です。テンプレート内の要素ではなく <app-plan-card> タグ自身にクラスが付くので、:host.selected でスタイルを当てます。
import { Component, input } from '@angular/core';
@Component({
selector: 'app-plan-card',
// 条件が true のとき <app-plan-card> に selected クラスが付く
host: {
'[class.selected]': 'isSelected()',
},
template: '<p>スタンダードプラン</p>',
styles: [':host.selected { border: 2px solid teal; }'],
})
export class PlanCardComponent {
isSelected = input(false);
}
2部品全体をクリックできるカードにする
host の '(click)' で、部品のどこを押してもメソッドが呼ばれるカードを作る例です。テンプレート内のボタンだけでなくタグ全体が反応するので、リンクカードのようなUIに向いています。
import { Component, input, output } from '@angular/core';
@Component({
selector: 'app-article-card',
// 部品のどこをクリックしても opened が発火する
host: {
'(click)': 'opened.emit(articleId())',
},
template: '<h3>{{ title() }}</h3><p>続きを読む…</p>',
styles: [':host { display: block; cursor: pointer; }'],
})
export class ArticleCardComponent {
articleId = input.required<number>();
title = input.required<string>();
opened = output<number>();
}
3属性とスタイルもバインドできる
host では class だけでなく '[attr.aria-expanded]' のような属性や '[style.opacity]' のようなスタイルもバインドできます。開閉状態をアクセシビリティ属性へ自動反映するなど、部品の状態と見た目・属性を1か所で結び付けられます。
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-accordion-item',
// 属性(attr.)もスタイル(style.)もホストへバインドできる
host: {
'[attr.aria-expanded]': 'isOpen()',
'[style.opacity]': 'isOpen() ? 1 : 0.6',
'(click)': 'toggle()',
},
template: '<p>クリックで開閉</p>',
})
export class AccordionItemComponent {
isOpen = signal(false);
toggle() {
this.isOpen.update((v) => !v);
}
}
4ディレクティブの host で相手の要素に作用する
host はディレクティブでも使えます。この場合バインド先は「ディレクティブが付けられた相手の要素」で、状態に応じたクラスの付け外しをクラスひとつで完結できます。ElementRef で直接スタイルを触るより宣言的に書けるのが利点です。
import { Directive, signal } from '@angular/core';
@Directive({
selector: '[appPressable]',
// 付けられた要素(ボタンなど)に押下中クラスを付ける
host: {
'[class.pressing]': 'pressing()',
'(mousedown)': 'pressing.set(true)',
'(mouseup)': 'pressing.set(false)',
'(mouseleave)': 'pressing.set(false)',
},
})
export class PressableDirective {
pressing = signal(false);
}
// 使う側: <button appPressable>押している間だけ凹む</button>
// CSS側に .pressing { transform: scale(0.97); } などを用意する
5キーボード操作をホストで受け取る
'(keydown.escape)' のようにキー名まで指定したイベントも host に書けます。ESCキーで閉じるパネルのようなキーボード対応が宣言的に書け、tabindex を属性として持たせればフォーカスを受け取れる要素になります。
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-side-panel',
// ESCキーが押されたら閉じる。tabindex でフォーカス可能にする
host: {
'tabindex': '0',
'(keydown.escape)': 'close()',
},
template:
'@if (isOpen()) {' +
' <div>パネルの中身(ESCで閉じる)</div>' +
'}',
})
export class SidePanelComponent {
isOpen = signal(true);
close() {
this.isOpen.set(false);
}
}