← 解説「カスタム属性ディレクティブ — 要素に振る舞いを足す」に戻る
サンプルコードで身につける: カスタム属性ディレクティブ — 要素に振る舞いを足す
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1最小のカスタムディレクティブ
ディレクティブの最小構成は、[名前] 形式の selector と、要素を触るための ElementRef だけです。属性を付けるだけで要素の背景が変わる、という「振る舞いの後付け」の核がこの数行に詰まっています。
import { Directive, ElementRef, inject } from '@angular/core';
@Directive({
selector: '[appMarker]', // 属性として付けるので [ ] で囲む
})
export class MarkerDirective {
private el = inject(ElementRef);
constructor() {
// 付けられた要素に蛍光ペン風の背景を敷く
this.el.nativeElement.style.backgroundColor = 'khaki';
}
}
2ホバーで背景色を変える
host にマウスイベントを登録し、乗ったときと離れたときで背景色を切り替える定番の例です。ElementRefで要素を触る処理とイベントへの反応を組み合わせると、ディレクティブは一気に実用的になります。
import { Directive, ElementRef, inject } from '@angular/core';
@Directive({
selector: '[appHoverHighlight]',
// ホスト要素のマウスイベントに反応する
host: {
'(mouseenter)': 'onEnter()',
'(mouseleave)': 'onLeave()',
},
})
export class HoverHighlightDirective {
private el = inject(ElementRef);
onEnter() {
this.el.nativeElement.style.backgroundColor = 'lightcyan';
}
onLeave() {
this.el.nativeElement.style.backgroundColor = '';
}
}
3input() でディレクティブに値を渡す
ディレクティブもコンポーネントと同じように input() で値を受け取れます。effect と組み合わせれば、親が渡す色が変わるたびに要素へ反映されます。使う側は <p appTint [appTint]... ではなく [tintColor]="..." のように通常の入力として渡します。
import { Directive, ElementRef, inject, input, effect } from '@angular/core';
@Directive({
selector: '[appTint]',
})
export class TintDirective {
private el = inject(ElementRef);
// ディレクティブも input() で値を受け取れる
tintColor = input('lightyellow');
constructor() {
// 入力が変わるたびに背景へ反映する
effect(() => {
this.el.nativeElement.style.backgroundColor = this.tintColor();
});
}
}
// 使う側: <p appTint tintColor="mistyrose">ピンクの段落</p>
4使う側は imports に登録して属性で付ける
自作ディレクティブはコンポーネントと同じく、使う側の imports への登録が必要です。1つのディレクティブを複数の要素に付けられるのがコンポーネントとの大きな違いで、同じ振る舞いをあちこちで再利用できます。
import { Component } from '@angular/core';
import { MarkerDirective } from './marker.directive';
@Component({
selector: 'app-notice-list',
// ディレクティブも imports に登録して使う
imports: [MarkerDirective],
// 同じ振る舞いを複数の要素へ自由に付けられる
template:
'<p appMarker>重要なお知らせ</p>' +
'<p>ふつうのお知らせ</p>' +
'<li appMarker>締め切りは金曜日</li>',
})
export class NoticeListComponent {}
5表示されたら自動でフォーカスする
画面に現れた入力欄へ自動でカーソルを入れる、実務でよく欲しくなるディレクティブです。描画が終わったあとに一度だけ実行したい処理は afterNextRender に書きます。モーダルを開いた直後の入力欄などに付けると効果的です。
import { Directive, ElementRef, inject, afterNextRender } from '@angular/core';
@Directive({
selector: '[appAutofocus]',
})
export class AutofocusDirective {
private el = inject(ElementRef);
constructor() {
// 描画が終わったあとに一度だけ実行される
afterNextRender(() => {
this.el.nativeElement.focus();
});
}
}
// 使う側: <input appAutofocus placeholder="検索">
// モーダルを開いた直後の入力欄などに付けると便利