11

我想经常用从 JSON REST API 中提取的新数据更新我的数据表(td-data-table与几个共价)。ng-template多于浏览器的行数,因此用户可能需要垂直滚动。但是当我更新表中的数据时,它会完全重绘,即垂直滚动位置重置为顶部,工具提示闪烁等。

用于保存/恢复垂直滚动的技巧,例如下面的工作,但它们会造成很多视觉混乱,尤其是在 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;
  }
});

我怎样才能干净地更新表(或任何组件)中的数据,而无需黑客重置滚动位置并忍受大量闪烁行为?

如果没有使用 Covalent 数据表的解决方案,是否有另一个 Angular 2+ 控件可以正确处理这个问题?

问题的动画屏幕截图:垂直滚动在数据更新时快速恢复。应在数据更新期间保持垂直滚动。 截屏

4

4 回答 4

9

您可以尝试使用 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>

然后在你的打字稿中:

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-cc147b5104e5 https://blog.angular-university.io/angular-2-ngfor/

此外,NGX-Datatable 非常适合这个用例。它内置了虚拟滚动。https://github.com/swimlane/ngx-datatable

于 2018-04-18T16:37:41.557 回答
2

我建议您切换到角度材料并将其绑定到可观察的数据源。

https://material.angular.io/components/table/overview#observable-stream-of-data-arrays

当数据源(Observable)用新数据更新时,它将更新 DOM,并且不需要跟随滚动事件。

如果您担心页面上列出的项目的数量以简单的方式支持分页;. https://material.angular.io/components/table/overview#pagination

旁注:切换到角度材料,因为它们的组件都有很好的文档记录,并带有示例和示例代码,如果您遇到困难,请告诉我。

于 2018-04-18T14:46:32.920 回答
1

将数据推送到 *ngFor 正在使用的同一数组变量不会重新渲染 html。

简单示例:https ://angular-frjdnf.stackblitz.io

编辑:

我使用 *ngFor 制作了一个带有共价表的示例项目,其中仅更新附加行而不重新渲染整个表。

链接到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++;
  }

}

希望这可以帮助。

于 2018-04-20T08:57:08.857 回答
0

看起来当您获得更多数据时,您正在刷新整个列表(*ngFor 中使用的数组),因此 Angular 再次重新绘制完整表格。尝试仅将差异数据推送到该数组。

于 2018-04-17T14:41:11.423 回答