詳細ガイド
ディレクティブ

属性ディレクティブ

属性ディレクティブを使用して、DOM要素とAngularコンポーネントの外観や動作を変更します。

属性ディレクティブの作成

このセクションでは、ホスト要素の背景色を黄色に設定するハイライトディレクティブを作成する方法について説明します。

  1. ディレクティブを作成するには、CLIコマンドng generate directiveを使用します。

          
    ng generate directive highlight

    CLIはsrc/app/highlight.directive.tsと、対応するテストファイルsrc/app/highlight.directive.spec.tsを作成します。

    src/app/highlight.directive.ts

          
    import {Directive} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {}

    @Directive()デコレーターの構成プロパティは、ディレクティブのCSS属性セレクター[appHighlight]を指定します。

  2. @angular/coreからElementRefをインポートします。 ElementRefは、nativeElementプロパティを通じてホストDOM要素(appHighlightを適用する要素)への直接アクセスを提供します。

  3. ディレクティブのconstructor()ElementRefを追加して、ホストDOM要素への参照を注入します。

  4. 背景を黄色に設定するロジックをHighlightDirectiveクラスに追加します。

    src/app/highlight.directive.ts

          
    import {Directive, ElementRef} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {    this.el.nativeElement.style.backgroundColor = 'yellow';  }}

HELPFUL: ディレクティブはネームスペースをサポートしていません。

src/app/app.component.avoid.html (unsupported)

      
<p app:Highlight>This is invalid</p>

属性ディレクティブの適用

  1. HighlightDirectiveを使用するには、ディレクティブを属性として持つ<p>要素をHTMLテンプレートに追加します。

    src/app/app.component.html

          
    <h1>My First Attribute Directive</h1><p appHighlight>Highlight me!</p><p appHighlight="yellow">Highlighted in yellow</p><p [appHighlight]="'orange'">Highlighted in orange</p><p [appHighlight]="color">Highlighted with parent component's color</p>

AngularはHighlightDirectiveクラスのインスタンスを作成し、<p>要素への参照をディレクティブのコンストラクターに注入します。これにより、<p>要素の背景スタイルが黄色に設定されます。

ユーザーイベントの処理

このセクションでは、ユーザーが要素内または要素外にマウスを移動したときに検出する方法と、ハイライトカラーを設定またはクリアして応答する方法について説明します。

  1. @angular/coreからHostListenerをインポートします。

    src/app/highlight.directive.ts (imports)

          
    import {Directive, ElementRef, HostListener} from '@angular/core';import {Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  2. マウスが入りまたは出たときに応答する2つのイベントハンドラーを追加します。それぞれに@HostListener()デコレーターを使用します。

    src/app/highlight.directive.ts (mouse-methods)

          
    import {Directive, ElementRef, HostListener} from '@angular/core';import {Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

@HostListener()デコレーターを使用して、属性ディレクティブをホストするDOM要素(この場合は<p>)のイベントを購読します。

HELPFUL: ハンドラーは、ホストDOM要素elに色を設定するヘルパーメソッドhighlight()に委任します。

完全なディレクティブは次のとおりです。

src/app/highlight.directive.ts

      
import {Directive, ElementRef, HostListener} from '@angular/core';import {Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

ポインタが段落要素の上にホバーすると背景色が表示され、ポインタが外れると背景色が消えます。

Second Highlight

属性ディレクティブに値を渡す

このセクションでは、HighlightDirectiveを適用するときにハイライトカラーを設定する方法について説明します。

  1. highlight.directive.tsで、@angular/coreからInputをインポートします。

    src/app/highlight.directive.ts (imports)

          
    import {Directive, ElementRef, HostListener, Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @Input() appHighlight = '';  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  2. appHighlight @Input()プロパティを追加します。

    src/app/highlight.directive.ts

          
    import {Directive, ElementRef, HostListener, Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @Input() appHighlight = '';  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

    @Input()デコレーターは、ディレクティブのappHighlightプロパティをバインディングで使用できるようにするメタデータをクラスに追加します。

  3. app.component.tsで、AppComponentcolorプロパティを追加します。

    src/app/app.component.ts (class)

          
    import {Component} from '@angular/core';import {HighlightDirective} from './highlight.directive';@Component({  selector: 'app-root',  templateUrl: './app.component.1.html',  imports: [HighlightDirective],})export class AppComponent {  color = 'yellow';}
  4. ディレクティブと色を同時に適用するには、appHighlightディレクティブセレクターを使用してプロパティバインディングを使用し、それをcolorに設定します。

    src/app/app.component.html (color)

          
    <h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr /><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr /><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

    [appHighlight]属性バインディングは次の2つのタスクを実行します。

    • <p>要素にハイライトディレクティブを適用する
    • プロパティバインディングを使用してディレクティブのハイライトカラーを設定する

ユーザー入力を使用して値を設定する

このセクションでは、カラー選択をappHighlightディレクティブにバインドするラジオボタンを追加する方法について説明します。

  1. 色を選択するためのマークアップをapp.component.htmlに追加します。

    src/app/app.component.html (v2)

          
    <h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr /><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr /><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>
  2. AppComponent.colorを修正して、初期値を持たないようにします。

    src/app/app.component.ts (class)

          
    import {Component} from '@angular/core';import {HighlightDirective} from './highlight.directive';@Component({  selector: 'app-root',  templateUrl: './app.component.html',  imports: [HighlightDirective],})export class AppComponent {  color = '';}
  3. highlight.directive.tsで、onMouseEnterメソッドを修正して、最初にappHighlightでハイライトしようとします。appHighlightundefinedの場合はredにフォールバックします。

    src/app/highlight.directive.ts (mouse-enter)

          
    import {Directive, ElementRef, HostListener, Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @Input() appHighlight = '';  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  4. アプリケーションを起動して、ユーザーがラジオボタンで色を選択できることを確認します。

    Animated gif of the refactored highlight directive changing color according to the radio button the user selects

2番目のプロパティにバインドする

このセクションでは、開発者がデフォルトカラーを設定できるようにアプリケーションを構成する方法について説明します。

  1. HighlightDirectivedefaultColorという名前の2番目のInput()プロパティを追加します。

    src/app/highlight.directive.ts (defaultColor)

          
    import {Directive, ElementRef, HostListener, Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @Input() defaultColor = '';  @Input() appHighlight = '';  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight || this.defaultColor || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  2. ディレクティブのonMouseEnterを修正して、最初にappHighlightでハイライトしようとします。次にdefaultColorでハイライトしようとします。両方のプロパティがundefinedの場合はredにフォールバックします。

    src/app/highlight.directive.ts (mouse-enter)

          
    import {Directive, ElementRef, HostListener, Input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  constructor(private el: ElementRef) {}  @Input() defaultColor = '';  @Input() appHighlight = '';  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight || this.defaultColor || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  3. AppComponent.colorにバインドし、デフォルトカラーとして「violet」を使用するには、次のHTMLを追加します。 この場合、defaultColorバインディングは、静的であるため、角括弧[]を使用しません。

    src/app/app.component.html (defaultColor)

          
    <h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr /><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr /><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

    コンポーネントと同様に、ホスト要素に複数のディレクティブプロパティバインディングを追加できます。

デフォルトカラーは、デフォルトカラーバインディングがない場合は赤です。 ユーザーが色を選択すると、選択した色がアクティブなハイライトカラーになります。

Animated gif of final highlight directive that shows red color with no binding and violet with the default color set. When user selects color, the selection takes precedence.

NgNonBindableを使用してAngularの処理を無効にする

ブラウザでの式評価を防ぐには、ホスト要素にngNonBindableを追加します。 ngNonBindableは、テンプレート内の補間、ディレクティブ、バインディングを無効にします。

次の例では、式{{ 1 + 1 }}はコードエディタと同じようにレンダリングされ、2は表示されません。

src/app/app.component.html

      
<h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr /><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr /><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

ngNonBindableを要素に適用すると、その要素の子要素のバインディングが停止します。 ただし、ngNonBindableは、ngNonBindableを適用した要素に対しては、ディレクティブを動作させます。 次の例では、appHighlightディレクティブはアクティブですが、Angularは式{{ 1 + 1 }}を評価しません。

src/app/app.component.html

      
<h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr /><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr /><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

ngNonBindableを親要素に適用すると、Angularは要素の子要素に対して、プロパティバインディングやイベントバインディングなどあらゆる種類の補間とバインディングを無効にします。