【Angular】コンポーネントはわかるけど、ディレクティブがわからない人のための記事
まず結論から
まずは、ディレクティブは、「コンポーネントから見た目(HTML&CSS)をなくしたもの」と思ってもらうといいです。(厳密には違いますが、正しいことはこの記事の最後に書きます。)
ソースコードを見てみよう
早速ですが、ディレクティブのソースコード例です。とりあえず細かい中身は無視してください。
(コードはStackblitzで公開しています https://stackblitz.com/edit/directive-sample )
なんとなくコンポーネントと似ているけど、@Componentじゃなくて@Directiveであること、HTMLやCSSの宣言を行っていないことがわかります。
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appChangeColorOnClick]'
})
export class ChangeColorOnClickDirective {
constructor(private el: ElementRef) { }
@Input() defaultColor: string;
@Input('appChangeColorOnClick') color: string;
@HostListener('click') onClick() {
this.el.nativeElement.style.backgroundColor = this.color || this.defaultColor;
}
}
使い方
@Directive({
selector: '[appChangeColorOnClick]'
})
selectorで宣言した名前[appChangeColorOnClick]で、他のコンポーネントから呼び出すことができます。(こういった部分もコンポーネントと似てますよね。)
呼び出す例がこちら。
<h1>Directive sample</h1>
<div class="test" [appChangeColorOnClick]="color">ここをクリックすると背景色が変わります</div>
<div class="test" [appChangeColorOnClick]="color" defaultColor="red">
ここをクリックすると背景色が変わります
</div>
divタグに指定しているのがおわかりいただけるでしょうか?こんなふうにHTMLタグやコンポーネントなど任意の要素に指定するという使い方をします。
要素に対し、引っ付き虫のようにディレクティブが引っ付くイメージをもっていただけると良いです。
実はこれがディレクティブのメリットであり、「1つディレクティブを作ってしまえば、いろんなものに引っ付けて使い回せる」のが便利なのです。
詳細にディレクティブのコードを見てみる
まずは言葉の定義ですが、先程の引っ付き虫を思い出してください。引っ付いた先のことを「ホスト要素」と呼びます。(今回だとdivタグ)
ElementRef
コンストラクタのElementRef型の引数に、ホスト要素への参照が注入されています。ElementRefのnativeElementプロパティにより、直接ホスト要素のDOMへのアクセスが可能です。
@Input
これはコンポーネントの@Inputと同じものだと考えてもらえばほぼ大丈夫ですが、よくよく見るとselectorと同じ名前のInputがありますね。これは同じ名前でディレクティブを呼び出しつつ値も渡すということを同時にできるようにするものです。
@HostListener
ホスト要素で起こったイベントを監視するのでHostListenerです。例えば'click'だと、ホスト要素をクリックされたときに実行する処理を書きます。今回の場合は、クリックされたら@Inputで渡された値に背景色を変えます。
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appChangeColorOnClick]'
})
export class ChangeColorOnClickDirective {
constructor(private el: ElementRef) { }
@Input() defaultColor: string;
@Input('appChangeColorOnClick') color: string;
@HostListener('click') onClick() {
this.el.nativeElement.style.backgroundColor = this.color || this.defaultColor;
}
}
より正確な話
ディレクティブ=「コンポーネントから見た目(HTML&CSS)をなくしたもの」という説明を最初にしましたが、これは実は逆で、コンポーネント=「ディレクティブに見た目をつけたもの」です。
Angular公式ドキュメントによると、ディレクティブは以下の3種類に分類されます。
- コンポーネント
- 構造ディレクティブ
- 属性ディレクティブ
今回紹介したディレクティブは「属性ディレクティブ」です。今回はオリジナルのディレクティブを作りましたが、有名なものだとFormsModuleに含まれる[ngModel]
や[formGroup]
なども属性ディレクティブです。
構造ディレクティブとは、例えば有名なものだと*ngIf
や*ngFor
などといった、DOMの構造自体を変更できるディレクティブです。構造ディレクティブは先頭にアスタリスク*
がつきます。こちらも自分オリジナルのものを作ることができます。(公式ドキュメントで、*ngIf
の逆を行う*appUnless
を作る というものがあります)
Discussion