有没有办法在数据更新时保留 PrimeNG 表滚动位置?

jal*_*200 6 javascript datatable typescript primeng angular

我目前正在开发一个使用 Angular 12 的 PrimeNG 12 表项目,但我在 Angular 的更改检测和表更新方面遇到了一些麻烦,特别是在尝试阻止 PrimeNGp-table在数据刷新时滚动回顶部时。

对于一些背景,我有一个服务(我们称之为LocationService),负责保存位置列表并每隔 500 毫秒更新一次。像下面这样:

位置.ts

interface Location {
    id: string;
    lat: number;
    lng: number
}
Run Code Online (Sandbox Code Playgroud)

位置.service.ts

// RxJS Behaviour Subjects
_locationUpdates$: BehaviorSubject<Location[]> = new BehaviorSubject<Location[]>([]);

// RxJS Observables
locationUpdates$: Observable<Location[]> = _locationUpdates.asObservable();

// Service Function
startUpdates() {

    // Called within a service
    timer(0, 500).subscribe(() => {
        this._locations.forEach(location => {
            location.lat = // ... some method to calculate new latitude
            location.lng = // ... some method to calculate new longitude
        });

        this._locationUpdates$.next(this._locations);
    });
}
Run Code Online (Sandbox Code Playgroud)

现在,我有一个组件,它订阅位置更新并将其显示为(Lat, Lng)a p-table,但也要求经度在 -45.0 到 45.0 度之间(其他组件可能没有此要求)。滚动顺序并不重要,尽管大多数时候它的顺序相同,因为行变化不大。

我目前正在像这样订阅它,使用虚拟滚动,因为可能有数百个潜在行:

位置组件.html

<ng-container *ngIf="locations$ | async as locations">
    <p-table
        dataKey="id"
        scrollHeight="flex"
        [rows]="100"
        [scrollable]="true"
        [value]="locations"
        [virtualScroll]="true"
        [virtualRowHeight]="34"
    >
        <ng-template pTemplate="header">
            <tr>
                <th>Latitude</th>
                <th>Longitude</th>
            </tr>
        </ng-template>

        <ng-template pTemplate="body" let-location>
            <tr>
                <td>{{ location.lat }}</td>
                <td>{{ location.lng }}</td>
            </tr>
        </ng-template>
    </p-table>
</ng-container>
Run Code Online (Sandbox Code Playgroud)

位置组件.ts

// RxJS observables
locations$: Observable<Location[]>;

// Constructor
constructor(private _locationService: LocationService) {
    locations$ = _locationService.locationUpdates$
        .pipe(
            map(locations => locations.filter(location => location.lng >= -45.0 && location.lng <= 45.0))
        )
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是,当我运行代码时,每次刷新数据时表格都会捕捉到顶部。我认为这是由于数组引用发生变化造成的。但是,如果我离开管道async并使用本地数组,只需在更新时对其进行修改,如下所示:

.subscribe(locations => {
    this._locations.splice(0, this._locations.length, ...locations.filter(location => location.lng >= -45.0 && location.lng <= 45.0));
    this._changeDetectorRef.detectChanges();
}
Run Code Online (Sandbox Code Playgroud)

Angular 没有检测到变化,即使他detectChanges()调用了(它似乎什么也没做)。使用诸如this._locations = this._locations.slice()另一种方式通知它之类的东西只会让我回到上面的问题。

我向你们提出的问题是:有人对我如何解决这个问题有任何建议吗?我的目标是每 X 毫秒刷新一次数据,但也允许用户在更新时滚动。

任何帮助将不胜感激!

jal*_*200 8

好吧,我设法找到了这背后的罪魁祸首 - PrimeNG 的默认表行为是resetScrollTop()每次应用新过滤器时调用该函数。

就我而言,我在表中添加了许多过滤器(文本过滤器、几个布尔过滤器等),这意味着每次表数据每 500 毫秒左右更新一次,这些过滤器都会重新应用,导致表格滚动位置不断重置(如此处的 PrimeNG 源代码所示)。

我设法通过简单地覆盖这个特定表的函数来以一种有点古怪的方式解决这个问题:

位置组件.html

<p-table #locationsTable ...> ... </p-table>
Run Code Online (Sandbox Code Playgroud)

位置组件.ts

ngAfterViewInit() {
    if (this.locationsTable != null) {
        this.locationsTable.resetScrollTop = function() { }
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎暂时解决了这个问题,尽管如果有人知道更好的方法,我总是愿意听到它。希望这个答案能够帮助将来遇到类似情况的其他人。