آنلاین

Built-in directives

Directiveها classهایی هستند که behavior اضافه‌ای به elementها در applicationهای Angular شما اضافه می‌کنند.

از directiveهای built-in در Angular برای مدیریت formها، listها، styleها و چیزهایی که کاربر می‌بیند استفاده کنید.

نوع‌های مختلف directive در Angular به این شکل‌اند:

Directive TypesDetails
Componentsهمراه با template استفاده می‌شوند. این نوع directive رایج‌ترین نوع directive است.
Attribute directivesظاهر یا behavior یک element، component یا directive دیگر را تغییر می‌دهند.
Structural directivesبا اضافه و حذف کردن DOM elementها، layout مربوط به DOM را تغییر می‌دهند.

این راهنما attribute directiveهای built-in را پوشش می‌دهد.

Attribute directiveهای built-in

Attribute directiveها به behavior مربوط به elementهای HTML، attributeها، propertyها و componentهای دیگر گوش می‌دهند و آن را modify می‌کنند.

رایج‌ترین attribute directiveها عبارت‌اند از:

Common directivesDetails
NgClassمجموعه‌ای از CSS classها را اضافه و حذف می‌کند.
NgStyleمجموعه‌ای از styleهای HTML را اضافه و حذف می‌کند.
NgModeltwo-way data binding را به یک HTML form element اضافه می‌کند.

اضافه و حذف کردن classها با NgClass

با ngClass چند CSS class را هم‌زمان اضافه یا حذف کنید.

Import کردن NgClass در component

برای استفاده از NgClass، آن را به list مربوط به imports در component اضافه کنید.

ts
import {NgClass} from '@angular/common';

@Component({
  /* ... */
  imports: [NgClass],
})
export class AppComponent {}

استفاده از NgClass با یک expression

روی elementی که می‌خواهید style دهید، [ngClass] را اضافه کنید و آن را برابر یک expression قرار دهید. در این حالت، isSpecial یک boolean است که در app.component.ts روی true تنظیم شده است. چون isSpecial برابر true است، ngClass کلاس special را روی <div> اعمال می‌کند.

app.component.html
<h1>Built-in Directives</h1>

<h2>Built-in attribute directives</h2>

<h3 id="ngModel">NgModel (two-way) Binding</h3>

<fieldset>
  <h4>NgModel examples</h4>
  <p>Current item name: {{ currentItem.name }}</p>
  <p>
    <label for="without">without NgModel:</label>
    <input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
  </p>

  <p>
    <!-- #docregion NgModel-1 -->
    <label for="example-ngModel">[(ngModel)]:</label>
    <input [(ngModel)]="currentItem.name" id="example-ngModel" />
    <!-- #enddocregion NgModel-1 -->
  </p>

  <p>
    <label for="example-change">(ngModelChange)="...name=$event":</label>
    <input
      [ngModel]="currentItem.name"
      (ngModelChange)="currentItem.name = $event"
      id="example-change"
    />
  </p>

  <p>
    <label for="example-uppercase"
      >(ngModelChange)="setUppercaseName($event)"
      <!-- #docregion uppercase -->
      <input
        [ngModel]="currentItem.name"
        (ngModelChange)="setUppercaseName($event)"
        id="example-uppercase"
      />
      <!-- #enddocregion uppercase -->
    </label>
  </p>
</fieldset>

<hr />
<h2 id="ngClass">NgClass Binding</h2>

<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
  <li>
    <label for="saveable">saveable</label>
    <input type="checkbox" [(ngModel)]="canSave" id="saveable" />
  </li>
  <li>
    <label for="modified">modified:</label>
    <input
      type="checkbox"
      [value]="!isUnchanged"
      (change)="isUnchanged = !isUnchanged"
      id="modified"
    />
  </li>
  <li>
    <label for="special"
      >special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
    /></label>
  </li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>

<div [ngClass]="currentClasses">
  This div should be {{ canSave ? '' : 'not' }} saveable,
  {{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
  clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>

<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>

<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>

<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->

<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
  >normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
  >xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
  This div should be {{ canSave ? 'italic' : 'plain' }},
  {{ isUnchanged ? 'normal weight' : 'bold' }} and,
  {{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>

<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
  <p>If isActive is true, app-item-detail will render:</p>
  <!-- #docregion NgIf-1 -->
  <app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
  <!-- #enddocregion NgIf-1 -->

  <button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
  Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>

<h4>NgIf binding with template (no *)</h4>

<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />

<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>

<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>

<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>

<hr />
<h2 id="ngFor">NgFor Binding</h2>

<div class="box">
  <!-- #docregion NgFor-1, NgFor-1-2 -->
  <div *ngFor="let item of items">{{ item.name }}</div>
  <!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>

<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
  <!-- #docregion NgFor-2, NgFor-1-2 -->
  <app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
  <!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>

<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion NgFor-3 -->
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
  <!-- #enddocregion NgFor-3 -->
</div>

<p>with <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>

<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>

<p><em>without</em> trackBy</p>
<div class="box">
  <div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>

  <div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
    Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
  </div>
</div>

<p>with trackBy</p>
<div class="box">
  <div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
    ({{ item.id }}) {{ item.name }}
  </div>

  <div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
    Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
  </div>
</div>

<br /><br /><br />

<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion trackBy -->
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
  <!-- #enddocregion trackBy -->
</div>

<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with trackBy and <em>space</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with <em>generic</em> trackById function</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>

<hr />
<h2>NgSwitch Binding</h2>

<p>Pick your favorite item</p>
<div>
  <label for="item-{{ i }}" *ngFor="let i of items">
    <div>
      <input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
        i.name
      }}
    </div>
  </label>
</div>

<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
  <app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
  <app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
  <app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
  <app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
  <!-- #enddocregion NgSwitch -->
  <!-- #docregion NgSwitch-div -->
  <div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
  <!-- #enddocregion NgSwitch-div -->
  <!-- #docregion NgSwitch -->
  <app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->

استفاده از NgClass با یک method

در مثال زیر، setCurrentClasses() property مربوط به currentClasses را با objectی set می‌کند که بر اساس state مربوط به true یا false سه property دیگر component، سه class را اضافه یا حذف می‌کند.

  1. برای استفاده از NgClass با یک method، آن method را به کلاس component اضافه کنید.

هر key در object یک نام CSS class است. اگر یک key برابر true باشد، ngClass آن class را اضافه می‌کند. اگر یک key برابر false باشد، ngClass آن class را حذف می‌کند.

app.component.ts
import {Component, OnInit} from '@angular/core';
import {JsonPipe, NgClass, NgStyle} from '@angular/common';
// #docregion import-ng-if
import {NgIf} from '@angular/common';
// #enddocregion import-ng-if
// #docregion import-ng-for
import {NgFor} from '@angular/common';
// #enddocregion import-ng-for
// #docregion import-ng-switch
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
// #enddocregion import-ng-switch
// #docregion import-forms-module
import {FormsModule} from '@angular/forms';
// #enddocregion import-forms-module
import {Item} from './item';
import {ItemDetailComponent} from './item-detail/item-detail.component';
import {ItemSwitchComponents} from './item-switch.component';
import {StoutItemComponent} from './item-switch.component';

// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
@Component({
  // #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],

  imports: [
    NgClass,
    NgStyle,
    // #docregion import-ng-if
    NgIf, // <-- import into the component
    // #enddocregion import-ng-if
    // #docregion import-ng-for
    NgFor, // <-- import into the component
    // #enddocregion import-ng-for
    // #docregion import-ng-switch
    NgSwitch, // <-- import into the component
    NgSwitchCase,
    NgSwitchDefault,
    // #enddocregion import-ng-switch
    // #docregion import-forms-module
    FormsModule, // <--- import into the component
    // #enddocregion import-forms-module
    JsonPipe,
    ItemDetailComponent,
    ItemSwitchComponents,
    StoutItemComponent,
    // #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  ],
})
export class AppComponent implements OnInit {
  // #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  canSave = true;
  isSpecial = true;
  isUnchanged = true;

  isActive = true;
  nullCustomer: string | null = null;
  currentCustomer = {
    name: 'Laura',
  };

  item!: Item; // defined to demonstrate template context precedence
  items: Item[] = [];

  // #docregion item
  currentItem!: Item;
  // #enddocregion item

  // trackBy change counting
  itemsNoTrackByCount = 0;
  itemsWithTrackByCount = 0;
  itemsWithTrackByCountReset = 0;
  itemIdIncrement = 1;

  // #docregion setClasses
  currentClasses: Record<string, boolean> = {};
  // #enddocregion setClasses

  // #docregion setStyles
  currentStyles: Record<string, string> = {};
  // #enddocregion setStyles

  ngOnInit() {
    this.resetItems();
    this.setCurrentClasses();
    this.setCurrentStyles();
    this.itemsNoTrackByCount = 0;
  }

  setUppercaseName(name: string) {
    this.currentItem.name = name.toUpperCase();
  }

  // #docregion setClasses
  setCurrentClasses() {
    // CSS classes: added/removed per current state of component properties
    this.currentClasses = {
      saveable: this.canSave,
      modified: !this.isUnchanged,
      special: this.isSpecial,
    };
  }
  // #enddocregion setClasses

  // #docregion setStyles
  setCurrentStyles() {
    // CSS styles: set per current state of component properties
    this.currentStyles = {
      'font-style': this.canSave ? 'italic' : 'normal',
      'font-weight': !this.isUnchanged ? 'bold' : 'normal',
      'font-size': this.isSpecial ? '24px' : '12px',
    };
  }
  // #enddocregion setStyles

  isActiveToggle() {
    this.isActive = !this.isActive;
  }

  giveNullCustomerValue() {
    this.nullCustomer = 'Kelly';
  }

  resetItems() {
    this.items = Item.items.map((item) => item.clone());
    this.currentItem = this.items[0];
    this.item = this.currentItem;
  }

  resetList() {
    this.resetItems();
    this.itemsWithTrackByCountReset = 0;
    this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
  }

  changeIds() {
    this.items.forEach((i) => (i.id += 1 * this.itemIdIncrement));
    this.itemsWithTrackByCountReset = -1;
    this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
    this.itemsWithTrackByCount = ++this.itemsWithTrackByCount;
  }

  clearTrackByCounts() {
    this.resetItems();
    this.itemsNoTrackByCount = 0;
    this.itemsWithTrackByCount = 0;
    this.itemIdIncrement = 1;
  }
  // #docregion trackByItems
  trackByItems(index: number, item: Item): number {
    return item.id;
  }
  // #enddocregion trackByItems

  trackById(index: number, item: any): number {
    return item.id;
  }

  getValue(event: Event): string {
    return (event.target as HTMLInputElement).value;
  }
  // #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
}
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  1. در template، property binding مربوط به ngClass را به currentClasses اضافه کنید تا classهای element تنظیم شوند:
app.component.html
<h1>Built-in Directives</h1>

<h2>Built-in attribute directives</h2>

<h3 id="ngModel">NgModel (two-way) Binding</h3>

<fieldset>
  <h4>NgModel examples</h4>
  <p>Current item name: {{ currentItem.name }}</p>
  <p>
    <label for="without">without NgModel:</label>
    <input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
  </p>

  <p>
    <!-- #docregion NgModel-1 -->
    <label for="example-ngModel">[(ngModel)]:</label>
    <input [(ngModel)]="currentItem.name" id="example-ngModel" />
    <!-- #enddocregion NgModel-1 -->
  </p>

  <p>
    <label for="example-change">(ngModelChange)="...name=$event":</label>
    <input
      [ngModel]="currentItem.name"
      (ngModelChange)="currentItem.name = $event"
      id="example-change"
    />
  </p>

  <p>
    <label for="example-uppercase"
      >(ngModelChange)="setUppercaseName($event)"
      <!-- #docregion uppercase -->
      <input
        [ngModel]="currentItem.name"
        (ngModelChange)="setUppercaseName($event)"
        id="example-uppercase"
      />
      <!-- #enddocregion uppercase -->
    </label>
  </p>
</fieldset>

<hr />
<h2 id="ngClass">NgClass Binding</h2>

<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
  <li>
    <label for="saveable">saveable</label>
    <input type="checkbox" [(ngModel)]="canSave" id="saveable" />
  </li>
  <li>
    <label for="modified">modified:</label>
    <input
      type="checkbox"
      [value]="!isUnchanged"
      (change)="isUnchanged = !isUnchanged"
      id="modified"
    />
  </li>
  <li>
    <label for="special"
      >special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
    /></label>
  </li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>

<div [ngClass]="currentClasses">
  This div should be {{ canSave ? '' : 'not' }} saveable,
  {{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
  clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>

<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>

<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>

<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->

<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
  >normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
  >xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
  This div should be {{ canSave ? 'italic' : 'plain' }},
  {{ isUnchanged ? 'normal weight' : 'bold' }} and,
  {{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>

<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
  <p>If isActive is true, app-item-detail will render:</p>
  <!-- #docregion NgIf-1 -->
  <app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
  <!-- #enddocregion NgIf-1 -->

  <button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
  Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>

<h4>NgIf binding with template (no *)</h4>

<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />

<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>

<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>

<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>

<hr />
<h2 id="ngFor">NgFor Binding</h2>

<div class="box">
  <!-- #docregion NgFor-1, NgFor-1-2 -->
  <div *ngFor="let item of items">{{ item.name }}</div>
  <!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>

<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
  <!-- #docregion NgFor-2, NgFor-1-2 -->
  <app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
  <!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>

<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion NgFor-3 -->
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
  <!-- #enddocregion NgFor-3 -->
</div>

<p>with <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>

<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>

<p><em>without</em> trackBy</p>
<div class="box">
  <div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>

  <div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
    Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
  </div>
</div>

<p>with trackBy</p>
<div class="box">
  <div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
    ({{ item.id }}) {{ item.name }}
  </div>

  <div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
    Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
  </div>
</div>

<br /><br /><br />

<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion trackBy -->
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
  <!-- #enddocregion trackBy -->
</div>

<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with trackBy and <em>space</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with <em>generic</em> trackById function</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>

<hr />
<h2>NgSwitch Binding</h2>

<p>Pick your favorite item</p>
<div>
  <label for="item-{{ i }}" *ngFor="let i of items">
    <div>
      <input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
        i.name
      }}
    </div>
  </label>
</div>

<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
  <app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
  <app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
  <app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
  <app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
  <!-- #enddocregion NgSwitch -->
  <!-- #docregion NgSwitch-div -->
  <div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
  <!-- #enddocregion NgSwitch-div -->
  <!-- #docregion NgSwitch -->
  <app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->

برای این use case، Angular classها را هنگام initialization و در صورت تغییرات ناشی از reassign شدن object مربوط به currentClasses اعمال می‌کند. مثال کامل در ابتدا با ngOnInit() و وقتی کاربر روی button مربوط به Refresh currentClasses کلیک می‌کند، setCurrentClasses() را فراخوانی می‌کند. این stepها برای پیاده‌سازی ngClass ضروری نیستند.

تنظیم inline styleها با NgStyle

Import کردن NgStyle در component

برای استفاده از NgStyle، آن را به list مربوط به imports در component اضافه کنید.

ts
import {NgStyle} from '@angular/common';

@Component({
  /* ... */
  imports: [NgStyle],
})
export class AppComponent {}

از NgStyle برای تنظیم هم‌زمان چند inline style بر اساس state مربوط به component استفاده کنید.

  1. برای استفاده از NgStyle، یک method به کلاس component اضافه کنید.

در مثال زیر، setCurrentStyles() property مربوط به currentStyles را با objectی set می‌کند که سه style را بر اساس state مربوط به سه property دیگر component تعریف می‌کند.

app.component.ts
import {Component, OnInit} from '@angular/core';
import {JsonPipe, NgClass, NgStyle} from '@angular/common';
// #docregion import-ng-if
import {NgIf} from '@angular/common';
// #enddocregion import-ng-if
// #docregion import-ng-for
import {NgFor} from '@angular/common';
// #enddocregion import-ng-for
// #docregion import-ng-switch
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
// #enddocregion import-ng-switch
// #docregion import-forms-module
import {FormsModule} from '@angular/forms';
// #enddocregion import-forms-module
import {Item} from './item';
import {ItemDetailComponent} from './item-detail/item-detail.component';
import {ItemSwitchComponents} from './item-switch.component';
import {StoutItemComponent} from './item-switch.component';

// #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
@Component({
  // #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],

  imports: [
    NgClass,
    NgStyle,
    // #docregion import-ng-if
    NgIf, // <-- import into the component
    // #enddocregion import-ng-if
    // #docregion import-ng-for
    NgFor, // <-- import into the component
    // #enddocregion import-ng-for
    // #docregion import-ng-switch
    NgSwitch, // <-- import into the component
    NgSwitchCase,
    NgSwitchDefault,
    // #enddocregion import-ng-switch
    // #docregion import-forms-module
    FormsModule, // <--- import into the component
    // #enddocregion import-forms-module
    JsonPipe,
    ItemDetailComponent,
    ItemSwitchComponents,
    StoutItemComponent,
    // #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  ],
})
export class AppComponent implements OnInit {
  // #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  canSave = true;
  isSpecial = true;
  isUnchanged = true;

  isActive = true;
  nullCustomer: string | null = null;
  currentCustomer = {
    name: 'Laura',
  };

  item!: Item; // defined to demonstrate template context precedence
  items: Item[] = [];

  // #docregion item
  currentItem!: Item;
  // #enddocregion item

  // trackBy change counting
  itemsNoTrackByCount = 0;
  itemsWithTrackByCount = 0;
  itemsWithTrackByCountReset = 0;
  itemIdIncrement = 1;

  // #docregion setClasses
  currentClasses: Record<string, boolean> = {};
  // #enddocregion setClasses

  // #docregion setStyles
  currentStyles: Record<string, string> = {};
  // #enddocregion setStyles

  ngOnInit() {
    this.resetItems();
    this.setCurrentClasses();
    this.setCurrentStyles();
    this.itemsNoTrackByCount = 0;
  }

  setUppercaseName(name: string) {
    this.currentItem.name = name.toUpperCase();
  }

  // #docregion setClasses
  setCurrentClasses() {
    // CSS classes: added/removed per current state of component properties
    this.currentClasses = {
      saveable: this.canSave,
      modified: !this.isUnchanged,
      special: this.isSpecial,
    };
  }
  // #enddocregion setClasses

  // #docregion setStyles
  setCurrentStyles() {
    // CSS styles: set per current state of component properties
    this.currentStyles = {
      'font-style': this.canSave ? 'italic' : 'normal',
      'font-weight': !this.isUnchanged ? 'bold' : 'normal',
      'font-size': this.isSpecial ? '24px' : '12px',
    };
  }
  // #enddocregion setStyles

  isActiveToggle() {
    this.isActive = !this.isActive;
  }

  giveNullCustomerValue() {
    this.nullCustomer = 'Kelly';
  }

  resetItems() {
    this.items = Item.items.map((item) => item.clone());
    this.currentItem = this.items[0];
    this.item = this.currentItem;
  }

  resetList() {
    this.resetItems();
    this.itemsWithTrackByCountReset = 0;
    this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
  }

  changeIds() {
    this.items.forEach((i) => (i.id += 1 * this.itemIdIncrement));
    this.itemsWithTrackByCountReset = -1;
    this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
    this.itemsWithTrackByCount = ++this.itemsWithTrackByCount;
  }

  clearTrackByCounts() {
    this.resetItems();
    this.itemsNoTrackByCount = 0;
    this.itemsWithTrackByCount = 0;
    this.itemIdIncrement = 1;
  }
  // #docregion trackByItems
  trackByItems(index: number, item: Item): number {
    return item.id;
  }
  // #enddocregion trackByItems

  trackById(index: number, item: any): number {
    return item.id;
  }

  getValue(event: Event): string {
    return (event.target as HTMLInputElement).value;
  }
  // #docregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
}
// #enddocregion import-ng-if, import-ng-for, import-ng-switch, import-forms-module
  1. برای تنظیم styleهای element، یک property binding از نوع ngStyle به currentStyles اضافه کنید.
app.component.html
<h1>Built-in Directives</h1>

<h2>Built-in attribute directives</h2>

<h3 id="ngModel">NgModel (two-way) Binding</h3>

<fieldset>
  <h4>NgModel examples</h4>
  <p>Current item name: {{ currentItem.name }}</p>
  <p>
    <label for="without">without NgModel:</label>
    <input [value]="currentItem.name" (input)="currentItem.name = getValue($event)" id="without" />
  </p>

  <p>
    <!-- #docregion NgModel-1 -->
    <label for="example-ngModel">[(ngModel)]:</label>
    <input [(ngModel)]="currentItem.name" id="example-ngModel" />
    <!-- #enddocregion NgModel-1 -->
  </p>

  <p>
    <label for="example-change">(ngModelChange)="...name=$event":</label>
    <input
      [ngModel]="currentItem.name"
      (ngModelChange)="currentItem.name = $event"
      id="example-change"
    />
  </p>

  <p>
    <label for="example-uppercase"
      >(ngModelChange)="setUppercaseName($event)"
      <!-- #docregion uppercase -->
      <input
        [ngModel]="currentItem.name"
        (ngModelChange)="setUppercaseName($event)"
        id="example-uppercase"
      />
      <!-- #enddocregion uppercase -->
    </label>
  </p>
</fieldset>

<hr />
<h2 id="ngClass">NgClass Binding</h2>

<p>currentClasses is {{ currentClasses | json }}</p>
<!-- #docregion NgClass-1 -->
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
<!-- #enddocregion NgClass-1 -->
<ul>
  <li>
    <label for="saveable">saveable</label>
    <input type="checkbox" [(ngModel)]="canSave" id="saveable" />
  </li>
  <li>
    <label for="modified">modified:</label>
    <input
      type="checkbox"
      [value]="!isUnchanged"
      (change)="isUnchanged = !isUnchanged"
      id="modified"
    />
  </li>
  <li>
    <label for="special"
      >special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"
    /></label>
  </li>
</ul>
<button type="button" (click)="setCurrentClasses()">Refresh currentClasses</button>

<div [ngClass]="currentClasses">
  This div should be {{ canSave ? '' : 'not' }} saveable,
  {{ isUnchanged ? 'unchanged' : 'modified' }} and {{ isSpecial ? '' : 'not' }} special after
  clicking "Refresh".
</div>
<br /><br />
<!-- #docregion special-div -->
<!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
<!-- #enddocregion special-div -->
<div class="helpful study course">Helpful study course</div>
<div [ngClass]="{'helpful': false, 'study': true, 'course': true}">Study course</div>

<!-- NgStyle binding -->
<hr />
<h3>NgStyle Binding</h3>
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">This div is x-large or smaller.</div>

<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
<p>currentStyles is {{ currentStyles | json }}</p>

<!-- #docregion NgStyle-2 -->
<div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>
<!-- #enddocregion NgStyle-2 -->

<br />
<label for="canSave">italic: <input id="canSave" type="checkbox" [(ngModel)]="canSave" /></label> |
<label for="isUnchanged"
  >normal: <input id="isUnchanged" type="checkbox" [(ngModel)]="isUnchanged"
/></label>
|
<label for="isSpecial"
  >xlarge: <input id="isSpecial" type="checkbox" [(ngModel)]="isSpecial"
/></label>
<button type="button" (click)="setCurrentStyles()">Refresh currentStyles</button>
<br /><br />
<div [ngStyle]="currentStyles">
  This div should be {{ canSave ? 'italic' : 'plain' }},
  {{ isUnchanged ? 'normal weight' : 'bold' }} and,
  {{ isSpecial ? 'extra large' : 'normal size' }} after clicking "Refresh".
</div>

<hr />
<h2>Built-in structural directives</h2>
<h3 id="ngIf">NgIf Binding</h3>
<div>
  <p>If isActive is true, app-item-detail will render:</p>
  <!-- #docregion NgIf-1 -->
  <app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
  <!-- #enddocregion NgIf-1 -->

  <button type="button" (click)="isActiveToggle()">Toggle app-item-detail</button>
</div>
<p>If currentCustomer isn't null, say hello to Laura:</p>
<!-- #docregion NgIf-2 -->
<div *ngIf="currentCustomer">Hello, {{ currentCustomer.name }}</div>
<!-- #enddocregion NgIf-2 -->
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
<!-- #docregion NgIf-2b -->
<div *ngIf="nullCustomer">
  Hello, <span>{{ nullCustomer }}</span>
</div>
<!-- #enddocregion NgIf-2b -->
<button type="button" (click)="giveNullCustomerValue()">Give nullCustomer a value</button>

<h4>NgIf binding with template (no *)</h4>

<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>
<hr />

<h4>Show/hide vs. NgIf</h4>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>

<p>ItemDetail is in the DOM but hidden</p>
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>

<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>

<hr />
<h2 id="ngFor">NgFor Binding</h2>

<div class="box">
  <!-- #docregion NgFor-1, NgFor-1-2 -->
  <div *ngFor="let item of items">{{ item.name }}</div>
  <!-- #enddocregion NgFor-1, NgFor-1-2 -->
</div>

<p>*ngFor with ItemDetailComponent element</p>
<div class="box">
  <!-- #docregion NgFor-2, NgFor-1-2 -->
  <app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
  <!-- #enddocregion NgFor-2, NgFor-1-2 -->
</div>

<h4 id="ngFor-index">*ngFor with index</h4>
<p>with <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion NgFor-3 -->
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
  <!-- #enddocregion NgFor-3 -->
</div>

<p>with <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; let i = index">{{ i + 1 }} - {{ item.name }}</div>
</div>

<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
<button type="button" (click)="resetList()">Reset items</button>
<button type="button" (click)="changeIds()">Change ids</button>
<button type="button" (click)="clearTrackByCounts()">Clear counts</button>

<p><em>without</em> trackBy</p>
<div class="box">
  <div #noTrackBy *ngFor="let item of items">({{ item.id }}) {{ item.name }}</div>

  <div id="noTrackByCnt" *ngIf="itemsNoTrackByCount">
    Item DOM elements change #{{ itemsNoTrackByCount }} without trackBy
  </div>
</div>

<p>with trackBy</p>
<div class="box">
  <div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">
    ({{ item.id }}) {{ item.name }}
  </div>

  <div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
    Item DOM elements change #{{ itemsWithTrackByCount }} with trackBy
  </div>
</div>

<br /><br /><br />

<p>with trackBy and <em>semi-colon</em> separator</p>
<div class="box">
  <!-- #docregion trackBy -->
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
  <!-- #enddocregion trackBy -->
</div>

<p>with trackBy and <em>comma</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with trackBy and <em>space</em> separator</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackByItems">({{ item.id }}) {{ item.name }}</div>
</div>

<p>with <em>generic</em> trackById function</p>
<div class="box">
  <div *ngFor="let item of items; trackBy: trackById">({{ item.id }}) {{ item.name }}</div>
</div>

<hr />
<h2>NgSwitch Binding</h2>

<p>Pick your favorite item</p>
<div>
  <label for="item-{{ i }}" *ngFor="let i of items">
    <div>
      <input id="item-{{ i }}" type="radio" name="items" [(ngModel)]="currentItem" [value]="i" />{{
        i.name
      }}
    </div>
  </label>
</div>

<!-- #docregion NgSwitch -->
<div [ngSwitch]="currentItem.feature">
  <app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
  <app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
  <app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
  <app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
  <!-- #enddocregion NgSwitch -->
  <!-- #docregion NgSwitch-div -->
  <div *ngSwitchCase="'bright'">Are you as bright as {{ currentItem.name }}?</div>
  <!-- #enddocregion NgSwitch-div -->
  <!-- #docregion NgSwitch -->
  <app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div>
<!-- #enddocregion NgSwitch -->

برای این use case، Angular styleها را هنگام initialization و در صورت تغییرات اعمال می‌کند. برای این کار، مثال کامل در ابتدا با ngOnInit() و وقتی propertyهای dependent از طریق click روی button تغییر می‌کنند، setCurrentStyles() را فراخوانی می‌کند. با این حال، این stepها برای پیاده‌سازی خود ngStyle ضروری نیستند.

قدم بعدی