آنلاین

Attribute directiveها

با attribute directiveها ظاهر یا behavior مربوط به DOM elementها و componentهای Angular را تغییر دهید.

ساخت یک attribute directive

این بخش شما را در ساخت یک highlight directive راهنمایی می‌کند که background color مربوط به host element را روی yellow تنظیم می‌کند.

  1. برای ساخت یک directive، از command مربوط به CLI یعنی ng generate directive استفاده کنید.

``shell ng generate directive highlight ``

CLI فایل src/app/highlight.directive.ts و یک test file متناظر به نام src/app/highlight.directive.spec.ts را می‌سازد.

```angular-ts import {Directive} from '@angular/core';

@Directive({ selector: '[appHighlight]', }) export class HighlightDirective {} ```

property مربوط به configuration در decorator مربوط به @Directive()، CSS attribute selector مربوط به directive یعنی [appHighlight] را مشخص می‌کند.

ElementRef از طریق property مربوط به nativeElement خود، دسترسی مستقیم به host DOM element می‌دهد.

  1. ElementRef و inject را از @angular/core import کنید.
  1. از inject استفاده کنید تا reference به host DOM element بگیرید؛ همان elementی که appHighlight را روی آن اعمال می‌کنید.
  1. به کلاس HighlightDirective logic اضافه کنید که background را روی yellow تنظیم کند.
highlight.directive.ts
// #docregion
import {Directive, ElementRef, inject} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
})
export class HighlightDirective {
  private el = inject(ElementRef);

  constructor() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }
}
AVOID
<p app:Highlight>This is invalid</p>

اعمال یک attribute directive

برای استفاده از HighlightDirective، یک element از نوع <p> به HTML template اضافه کنید و directive را به‌عنوان attribute روی آن بگذارید.

app.component.html
<!-- #docregion -->
<h1>My First Attribute Directive</h1>
<!-- #docregion applied -->
<p appHighlight>Highlight me!</p>
<!-- #enddocregion applied  -->

<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 یک instance از کلاس HighlightDirective می‌سازد؛ این کلاس با inject(ElementRef) یک reference به element مربوط به <p> می‌گیرد و background style آن را روی yellow تنظیم می‌کند.

مدیریت eventهای کاربر

این بخش نشان می‌دهد چگونه تشخیص دهید کاربر mouse را وارد element یا از آن خارج می‌کند و در پاسخ، highlight color را تنظیم یا پاک کنید.

  1. Host event bindingها را با استفاده از property مربوط به host در decorator مربوط به @Directive() configure کنید.
src/app/highlight.directive.ts (decorator)
// #docplaster
// #docregion imports
import {Directive, ElementRef, inject} from '@angular/core';
// #enddocregion imports
// #docregion

// #docregion decorator
@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
// #enddocregion decorator
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion mouse-methods
  onMouseEnter() {
    this.highlight('yellow');
  }

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
  // #enddocregion mouse-methods
}
// #enddocregion
  1. دو event handler method اضافه کنید و eventهای host element را از طریق property مربوط به host به آن‌ها map کنید.
highlight.directive.ts (mouse-methods)
// #docplaster
// #docregion imports
import {Directive, ElementRef, inject} from '@angular/core';
// #enddocregion imports
// #docregion

// #docregion decorator
@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
// #enddocregion decorator
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion mouse-methods
  onMouseEnter() {
    this.highlight('yellow');
  }

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
  // #enddocregion mouse-methods
}
// #enddocregion

با configure کردن event listenerها روی host property مربوط به directive، به eventهای DOM elementی که میزبان attribute directive است subscribe کنید؛ در اینجا element مربوط به <p>.

Directive کامل به این شکل است:

highlight.directive.ts
// #docplaster
// #docregion imports
import {Directive, ElementRef, inject} from '@angular/core';
// #enddocregion imports
// #docregion

// #docregion decorator
@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
// #enddocregion decorator
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion mouse-methods
  onMouseEnter() {
    this.highlight('yellow');
  }

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
  // #enddocregion mouse-methods
}
// #enddocregion

Background color وقتی pointer روی paragraph element hover می‌کند ظاهر می‌شود و وقتی pointer خارج می‌شود ناپدید می‌شود.

Second Highlight

پاس دادن value به یک attribute directive

این بخش شما را در تنظیم highlight color هنگام اعمال HighlightDirective راهنمایی می‌کند.

  1. در highlight.directive.ts، input را از @angular/core import کنید.
highlight.directive.ts (imports)
// #docregion, imports
import {Directive, ElementRef, inject, input} from '@angular/core';
// #enddocregion imports

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion input
  appHighlight = input('');
  // #enddocregion input

  // #docregion mouse-enter
  onMouseEnter() {
    this.highlight(this.appHighlight() || 'red');
  }
  // #enddocregion mouse-enter

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}
  1. یک input property به نام appHighlight اضافه کنید.
highlight.directive.ts
// #docregion, imports
import {Directive, ElementRef, inject, input} from '@angular/core';
// #enddocregion imports

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion input
  appHighlight = input('');
  // #enddocregion input

  // #docregion mouse-enter
  onMouseEnter() {
    this.highlight(this.appHighlight() || 'red');
  }
  // #enddocregion mouse-enter

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

تابع input() metadataای به class اضافه می‌کند که property مربوط به appHighlight در directive را برای binding در دسترس قرار می‌دهد.

  1. در app.component.ts، یک property به نام color به AppComponent اضافه کنید.
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],
})
// #docregion class
export class AppComponent {
  color = 'yellow';
}
  1. برای اینکه directive و color را هم‌زمان اعمال کنید، از property binding با selector مربوط به directive یعنی appHighlight استفاده کنید و آن را برابر color قرار دهید.
app.component.html (color)
<!-- #docregion 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>
<!-- #docregion color -->
<p [appHighlight]="color">Highlight me!</p>
<!-- #enddocregion color, v2 -->

<!-- #docregion defaultColor -->
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
<!-- #enddocregion defaultColor, -->

<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>
<!-- #docregion ngNonBindable -->
<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
<!-- #enddocregion ngNonBindable -->

<!-- #docregion ngNonBindable-with-directive -->
<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>
<!-- #enddocregion ngNonBindable-with-directive -->

Attribute binding مربوط به [appHighlight] دو کار انجام می‌دهد:

  • highlighting directive را روی element مربوط به <p> اعمال می‌کند
  • highlight color مربوط به directive را با property binding تنظیم می‌کند

تنظیم value با input کاربر

این بخش شما را در اضافه کردن radio buttonها راهنمایی می‌کند تا انتخاب color خود را به directive مربوط به appHighlight bind کنید.

  1. Markup زیر را برای انتخاب color به app.component.html اضافه کنید:
app.component.html (v2)
<!-- #docregion 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>
<!-- #docregion color -->
<p [appHighlight]="color">Highlight me!</p>
<!-- #enddocregion color, v2 -->

<!-- #docregion defaultColor -->
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
<!-- #enddocregion defaultColor, -->

<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>
<!-- #docregion ngNonBindable -->
<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
<!-- #enddocregion ngNonBindable -->

<!-- #docregion ngNonBindable-with-directive -->
<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>
<!-- #enddocregion ngNonBindable-with-directive -->
  1. AppComponent.color را طوری revise کنید که مقدار اولیه نداشته باشد.
app.component.ts (class)
// #docregion
import {Component} from '@angular/core';
import {HighlightDirective} from './highlight.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  imports: [HighlightDirective],
})
// #docregion class
export class AppComponent {
  color = '';
}
  1. در highlight.directive.ts، method مربوط به onMouseEnter را revise کنید تا ابتدا با appHighlight highlight کند و اگر appHighlight برابر undefined بود، به red fallback کند.
highlight.directive.ts (mouse-enter)
// #docregion, imports
import {Directive, ElementRef, inject, input} from '@angular/core';
// #enddocregion imports

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion input
  appHighlight = input('');
  // #enddocregion input

  // #docregion mouse-enter
  onMouseEnter() {
    this.highlight(this.appHighlight() || 'red');
  }
  // #enddocregion mouse-enter

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}
  1. Application خود را serve کنید تا verify کنید کاربر می‌تواند با radio buttonها color را انتخاب کند.
Animated gif of the refactored highlight directive changing color according to the radio button the user selects

Binding به یک property دوم

این بخش شما را در configure کردن application راهنمایی می‌کند تا developer بتواند default color را set کند.

  1. یک input() property دوم به نام defaultColor به HighlightDirective اضافه کنید.
highlight.directive.ts (defaultColor)
import {Directive, ElementRef, inject, input} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion defaultColor
  defaultColor = input('');
  // #enddocregion defaultColor

  appHighlight = input('');

  // #docregion mouse-enter
  onMouseEnter() {
    this.highlight(this.appHighlight() || this.defaultColor() || 'red');
  }
  // #enddocregion mouse-enter

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}
  1. onMouseEnter مربوط به directive را revise کنید تا ابتدا با appHighlight highlight کند، سپس با defaultColor، و اگر هر دو property برابر undefined بودند، به red fallback کند.
highlight.directive.ts (mouse-enter)
import {Directive, ElementRef, inject, input} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  // #docregion defaultColor
  defaultColor = input('');
  // #enddocregion defaultColor

  appHighlight = input('');

  // #docregion mouse-enter
  onMouseEnter() {
    this.highlight(this.appHighlight() || this.defaultColor() || 'red');
  }
  // #enddocregion mouse-enter

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

در این حالت، binding مربوط به defaultColor از square bracket یعنی [] استفاده نمی‌کند، چون مقدار یک static string است، نه dynamic expression.

  1. برای bind کردن به AppComponent.color و fallback به "violet" به‌عنوان default color، HTML زیر را اضافه کنید.
app.component.html (defaultColor)
<!-- #docregion 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>
<!-- #docregion color -->
<p [appHighlight]="color">Highlight me!</p>
<!-- #enddocregion color, v2 -->

<!-- #docregion defaultColor -->
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
<!-- #enddocregion defaultColor, -->

<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>
<!-- #docregion ngNonBindable -->
<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
<!-- #enddocregion ngNonBindable -->

<!-- #docregion ngNonBindable-with-directive -->
<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>
<!-- #enddocregion ngNonBindable-with-directive -->

مثل componentها، می‌توانید چند directive property binding به یک host element اضافه کنید.

اگر default color binding وجود نداشته باشد، default color برابر red است. وقتی کاربر یک color انتخاب می‌کند، color انتخاب‌شده به active highlight color تبدیل می‌شود.

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.

غیرفعال کردن پردازش Angular با NgNonBindable

برای جلوگیری از evaluate شدن expression در مرورگر، ngNonBindable را به host element اضافه کنید. ngNonBindable interpolation، directiveها و binding را در templateها غیرفعال می‌کند.

در مثال زیر، expression مربوط به {{ 1 + 1 }} دقیقا همان‌طور render می‌شود که در code editor شما دیده می‌شود و 2 نمایش داده نمی‌شود.

app.component.html
<!-- #docregion 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>
<!-- #docregion color -->
<p [appHighlight]="color">Highlight me!</p>
<!-- #enddocregion color, v2 -->

<!-- #docregion defaultColor -->
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
<!-- #enddocregion defaultColor, -->

<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>
<!-- #docregion ngNonBindable -->
<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
<!-- #enddocregion ngNonBindable -->

<!-- #docregion ngNonBindable-with-directive -->
<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>
<!-- #enddocregion ngNonBindable-with-directive -->

اعمال ngNonBindable روی یک element، binding را برای child elementهای آن element متوقف می‌کند. با این حال، ngNonBindable همچنان اجازه می‌دهد directiveها روی همان elementی که ngNonBindable را اعمال کرده‌اید کار کنند. در مثال زیر، directive مربوط به appHighlight همچنان active است، اما Angular expression مربوط به {{ 1 + 1 }} را evaluate نمی‌کند.

app.component.html
<!-- #docregion 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>
<!-- #docregion color -->
<p [appHighlight]="color">Highlight me!</p>
<!-- #enddocregion color, v2 -->

<!-- #docregion defaultColor -->
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
<!-- #enddocregion defaultColor, -->

<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>
<!-- #docregion ngNonBindable -->
<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
<!-- #enddocregion ngNonBindable -->

<!-- #docregion ngNonBindable-with-directive -->
<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>
<!-- #enddocregion ngNonBindable-with-directive -->

اگر ngNonBindable را روی یک parent element اعمال کنید، Angular interpolation و هر نوع binding مثل property binding یا event binding را برای childهای آن element غیرفعال می‌کند.