データテーブルを頻繁に更新したい(共有結合td-data-table
いくつかのng-template
)JSONから取得した新しいデータを使用REST API。ブラウザに収まるよりも多くの行があるため、ユーザーは垂直方向にスクロールする必要があります。しかし、テーブルのデータを更新すると、完全に再描画されます。垂直スクロール位置が上にリセットされ、ツールチップが点滅します。
たとえば、ハック以下のような作業のような垂直スクロールを保存/復元しますが、特にFirefoxでは多くの視覚的な混乱を引き起こします。
// save vertical scroll
this.scrollTop = this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop;
// update table data here
this.data = newData;
// restore vertical scroll
setImmediate(() => {
this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop = this.scrollTop;
}
});
スクロール位置をリセットするためにハッキングしたり、多くの点滅動作に我慢したりせずに、テーブル(または実際には任意のコンポーネント)のデータをクリーンに更新するにはどうすればよいですか?
共有データテーブルを使用した解決策がない場合、これを適切に処理する別のAngular 2+コントロールはありますか?
問題のアニメーションスクリーンキャプチャ:データが更新されると、垂直スクロールがスナップバックします。垂直スクロールは、データの更新全体で維持する必要があります。
angularマテリアルに切り替えて、監視可能なデータソースにバインドすることをお勧めします。
https://material.angular.io/components/table/overview#observable-stream-of-data-arrays
Datasource(Observable)が新しいデータで更新されると、DOMが更新され、スクロールイベントを追跡する必要がなくなります。
ページにリストされているアイテムの数が心配な場合は、簡単な方法でページ付けをサポートします。 。 https://material.angular.io/components/table/overview#pagination
補足:コンポーネントが十分に文書化されているため、angularマテリアルに切り替え、例とサンプルコードを使用してください。行き詰まった場合に備えてお知らせください。
TrackBy関数を使用してみてください。この関数は、再描画を最適化するために*ngFor
のどの行が変更されたかを判別するために使用されます。
<tbody>
<tr td-data-table-row *ngFor="let row of basicData; trackBy: getRowId">
<td td-data-table-cell *ngFor="let column of columns" [numeric]="column.numeric">
{{column.format ? column.format(row[column.name]) : row[column.name]}}
</td>
<td td-data-table-cell (click)="openPrompt(row, 'comments')">
<button mat-button [class.mat-accent]="!row['comments']">{{row['comments'] || 'Add Comment'}}</button>
</td>
</tr>
</tbody>
そして、TypeScriptで:
getRowById(index, row) {
// Return some unique primitive idenitifier (string, number, etc.)
return row['some unique property'];
}
trackBy
の詳細については、以下を確認してください。
https://netbasal.com/angular-2-improve-performance-with-trackby-cc147b5104e5https://blog.angular-university.io/angular-2-ngfor/
また、NGX-Datatableは、このユースケースで非常にうまく機能します。仮想スクロールが組み込まれています。 https://github.com/swimlane/ngx-datatable
* ngForで使用されているのと同じ配列変数にデータをプッシュしてもhtmlは再レンダリングされません。
簡単な例: https://angular-frjdnf.stackblitz.io
編集:
* ngFor with angularを使用して、共有テーブルを使用してサンプルプロジェクトを作成しました。追加の行のみを更新し、テーブル全体を再レンダリングしません。
リンク先 Stackblitz.ioサンプルプロジェクト 。
[〜#〜] html [〜#〜]
<button (click)="addData()">Add Data</button>
<table td-data-table>
<thead>
<tr td-data-table-column-row>
<td td-data-table-column *ngFor="let column of columns">
{{column.label}}
</td>
</tr>
</thead>
<tbody>
<tr td-data-table-row *ngFor="let row of basicData">
<td td-data-table-cell *ngFor="let column of columns">
{{ row[column.name] }}
</td>
</tr>
</tbody>
</table>
[〜#〜] ts [〜#〜]
basicData
にはテーブルにロードされた初期データがあり、スクロールバーをテストする目的で[データの追加]ボタンをクリックしてダミーデータをbasicData
にプッシュしています。
import { Component } from '@angular/core';
import { ITdDataTableColumn } from '@covalent/core/data-table';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
columns: ITdDataTableColumn[] = [
{ name: 'first_name', label: 'First Name' },
{ name: 'last_name', label: 'Last Name' },
{ name: 'gender', label: 'Gender' }
];
count = 0;
basicData: any[] = [
{
"first_name": "Sully",
"gender": "Male",
"last_name": "Clutterham"
},
...
]
additionalData: any[] = [
{
"first_name": "Sully",
"gender": "Male",
"last_name": "Clutterham"
},
...
]
addData(){
if(this.count >= this.additionalData.length)
this.count = 0;
this.basicData.Push(this.additionalData[this.count]);
this.count++;
}
}
お役に立てれば。
より多くのデータを取得すると、リスト全体(* ngForで使用される配列)が更新されているように見えるため、angularはテーブル全体を再描画します。差分データのみをその配列にプッシュしてみてください。