web-dev-qa-db-ja.com

Angular 5データテーブルを更新するときに垂直スクロールを維持する方法は?

データテーブルを頻繁に更新したい(共有結合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+コントロールはありますか?

問題のアニメーションスクリーンキャプチャ:データが更新されると、垂直スクロールがスナップバックします。垂直スクロールは、データの更新全体で維持する必要があります。 screencapture

8
bunt

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マテリアルに切り替え、例とサンプルコードを使用してください。行き詰まった場合に備えてお知らせください。

2
steve biko

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

7
Pearman

* 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++;
  }

}

お役に立てれば。

0
gowtham raj j

より多くのデータを取得すると、リスト全体(* ngForで使用される配列)が更新されているように見えるため、angularはテーブル全体を再描画します。差分データのみをその配列にプッシュしてみてください。

0
Pradeep