開発覚書はてな版

個人的な開発関連の備忘録

【Angular】TrackByFunction内でthisを使用する

概要

以前の記事で ngFortrackBy についての記事を記述しました。

kakkoyakakko2.hatenablog.com

TrackByFunction内の thisDefaultIterableDiffer になります。
定義元のコンポーネントthis としたい場合は TrackByFunction を返すメソッドを作成して、そのメソッドを テンプレートの trackBy 内で呼び出す用にします。

使用ケースとしては一意キーを外部から指定する場合などに使用します。

実行環境

  • Node.js 10.9.x

使用ライブラリ

  • Angular 7.1.x

サンプルソース

list.component.ts
import { Component, Input, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'custom-list',
  template: `<li>{{num}}</li>`
})
export class ListComponent implements OnInit, OnDestroy {

  @Input() num = 0;

  @Input() title = 'list';

  ngOnInit(): void {
    console.log(`${this.title}: init - ${this.num}`);
  }

  ngOnDestroy(): void {
    console.log(`${this.title}: destroy - ${this.num}`);
  }
}
app.component.html
<div style="margin-top: 10px;">
  <div>
    <h4>
      Non trackBy
    </h4>
    <div>
      <button (click)="setItem1()">Apply</button>
    </div>
    <div>
      <ul>
        <ng-container *ngFor="let item of item1">
          <custom-list [num]="item.id" title="non-trackBy"></custom-list>
        </ng-container>
      </ul>
    </div>
  </div>
  <div style="margin-top: 10px;">
    <h4>
      trackBy
    </h4>
    <div>
      <button (click)="setItem2()">Apply</button>
    </div>
    <div>
      <ul>
        <ng-container *ngFor="let item of item2; trackBy: trackByItemFunc()">
          <custom-list [num]="item.id" title="trackBy"></custom-list>
        </ng-container>
      </ul>
    </div>
  </div>
</div>
app.component.ts
import { Component, TrackByFunction } from "@angular/core";

interface ListData {
  id: number;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  item1: ListData[] = [];
  item2: ListData[] = [];
  key = 'id';

  setItem1(): void {
    this.item1 = this.createList();
  }

  setItem2(): void {
    this.item2 = this.createList();
  }

  /**
   * ngFor trackBy setting.
   */
  trackByItemFunc(): TrackByFunction<ListData> {
    return (index, value) => {
      return value ? value[this.key] : null;
    };
  }

  private createList(): ListData[] {
    const items = new Array<ListData>();
    const length = Math.floor(Math.random() * 7) + 3;
    for (let i = 0; i < length; i++) {
      while (true) {
        const value = Math.floor(Math.random() * 10) + 1;
        if (items.findIndex(item => item.id === value) < 0) {
          items.push({ id: value });
          break;
        }
      }
    }
    return items;
  }
}

サンプルソース一式

github.com