有没有办法在数据更新时保留 PrimeNG table 滚动位置?
Is there a way to preserve PrimeNG table scroll position on data update?
我目前正在使用 Angular 12 使用 PrimeNG 12 tables 进行一个项目,但是我在 Angular 的变化检测和table 更新,特别是试图阻止 PrimeNG p-table
在数据刷新时滚动回顶部。
对于某些背景,我有一个服务(让我们称之为 LocationService
)负责保存位置列表并每隔 500 毫秒更新一次。类似于以下内容:
location.ts
interface Location {
id: string;
lat: number;
lng: number
}
location.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);
});
}
现在,我有一个组件可以订阅位置更新并将它们显示为 p-table
中的 (Lat, Lng)
,但还要求经度在 -45.0 和 45.0 之间学位(其他组件可能没有此要求)。滚动顺序无关紧要,尽管大多数时候它的顺序相同,因为行变化不大。
我目前是这样订阅的,使用虚拟滚动,因为可能有数百行:
位置-component.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>
位置-component.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))
)
}
这里的问题是,当我 运行 代码时,每次刷新数据时 table 都会跳到顶部。我认为这是由于数组引用发生了变化。但是,如果我离开 async
管道并使用本地数组,只需在更新时修改它,如下所示:
.subscribe(locations => {
this._locations.splice(0, this._locations.length, ...locations.filter(location => location.lng >= -45.0 && location.lng <= 45.0));
this._changeDetectorRef.detectChanges();
}
Angular 没有检测到变化,即使他 detectChanges()
调用(它似乎什么也没做)。使用 this._locations = this._locations.slice()
之类的东西以另一种方式通知它只会让我回到上面的问题。
我想问大家的问题是:有人对我如何解决这个问题有任何建议吗?我的目标是每 X 毫秒刷新一次数据,但也允许用户在更新时滚动。
如有任何帮助,我们将不胜感激!
好的,所以我设法找到了这背后的罪魁祸首 - PrimeNG 的默认 table 行为是每次应用新过滤器时调用函数 resetScrollTop()
。
在我的例子中,我在 table 中添加了一些过滤器(文本过滤器、几个布尔过滤器等),这意味着每次更新 table 数据每隔 500 毫秒左右,就会重新应用这些过滤器,导致 table 滚动位置不断重置 (as seen in the PrimeNG source here)。
我通过简单地覆盖这个特定 table:
的函数,设法以一种有点老套的方式解决了这个问题
位置-component.html
<p-table #locationsTable ...> ... </p-table>
位置-component.ts
ngAfterViewInit() {
if (this.locationsTable != null) {
this.locationsTable.resetScrollTop = function() { }
}
}
这似乎暂时解决了这个问题,但如果有人知道更好的方法,我总是乐于听取。希望这个答案对以后遇到类似情况的其他人有所帮助。
我目前正在使用 Angular 12 使用 PrimeNG 12 tables 进行一个项目,但是我在 Angular 的变化检测和table 更新,特别是试图阻止 PrimeNG p-table
在数据刷新时滚动回顶部。
对于某些背景,我有一个服务(让我们称之为 LocationService
)负责保存位置列表并每隔 500 毫秒更新一次。类似于以下内容:
location.ts
interface Location {
id: string;
lat: number;
lng: number
}
location.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);
});
}
现在,我有一个组件可以订阅位置更新并将它们显示为 p-table
中的 (Lat, Lng)
,但还要求经度在 -45.0 和 45.0 之间学位(其他组件可能没有此要求)。滚动顺序无关紧要,尽管大多数时候它的顺序相同,因为行变化不大。
我目前是这样订阅的,使用虚拟滚动,因为可能有数百行:
位置-component.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>
位置-component.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))
)
}
这里的问题是,当我 运行 代码时,每次刷新数据时 table 都会跳到顶部。我认为这是由于数组引用发生了变化。但是,如果我离开 async
管道并使用本地数组,只需在更新时修改它,如下所示:
.subscribe(locations => {
this._locations.splice(0, this._locations.length, ...locations.filter(location => location.lng >= -45.0 && location.lng <= 45.0));
this._changeDetectorRef.detectChanges();
}
Angular 没有检测到变化,即使他 detectChanges()
调用(它似乎什么也没做)。使用 this._locations = this._locations.slice()
之类的东西以另一种方式通知它只会让我回到上面的问题。
我想问大家的问题是:有人对我如何解决这个问题有任何建议吗?我的目标是每 X 毫秒刷新一次数据,但也允许用户在更新时滚动。
如有任何帮助,我们将不胜感激!
好的,所以我设法找到了这背后的罪魁祸首 - PrimeNG 的默认 table 行为是每次应用新过滤器时调用函数 resetScrollTop()
。
在我的例子中,我在 table 中添加了一些过滤器(文本过滤器、几个布尔过滤器等),这意味着每次更新 table 数据每隔 500 毫秒左右,就会重新应用这些过滤器,导致 table 滚动位置不断重置 (as seen in the PrimeNG source here)。
我通过简单地覆盖这个特定 table:
的函数,设法以一种有点老套的方式解决了这个问题位置-component.html
<p-table #locationsTable ...> ... </p-table>
位置-component.ts
ngAfterViewInit() {
if (this.locationsTable != null) {
this.locationsTable.resetScrollTop = function() { }
}
}
这似乎暂时解决了这个问题,但如果有人知道更好的方法,我总是乐于听取。希望这个答案对以后遇到类似情况的其他人有所帮助。