Closed ghenry22 closed 1 year ago
Update: enabling viewCache seems to resolve this, could be worthwhile adding this behaviour to the documentation or enabling the view cache by default.
Restoring the previous scroll position is out of scope for this library. The component responds to native HTML scroll events, so you should be able to use other generic solutions for restoring scroll position on navigation changes, such as the examples described here and here.
Additionally, here’s an example of a simple way to track and restore scroll positions for any kind of list, including virtual scroll lists using a basic directive and service:
Service:
import { Injectable } from '@angular/core';
export interface SavedScrollPosition {
position: number;
}
@Injectable()
export class ScrollTracker {
private scrollPositions: Record<string, SavedScrollPosition> = {};
public saveScrollPosition(elementId: string, scrollPosition: SavedScrollPosition) {
this.scrollPositions[elementId] = scrollPosition;
}
public getScrollPosition(elementId: string): SavedScrollPosition {
return this.scrollPositions[elementId];
}
}
Directive:
import { Directive, ElementRef, Input } from '@angular/core';
import { ScrollTracker } from './scroll-tracker.service';
import { Observable, fromEvent } from 'rxjs';
import { debounceTime, delay } from 'rxjs/operators';
import { AfterViewInit } from '@lithiumjs/angular';
@Directive({
selector: '[scrollTracker]',
standalone: true
})
export class ScrollTrackerDirective {
@Input('scrollTracker')
public elementId!: string;
@AfterViewInit()
private readonly afterViewInit$!: Observable<void>;
private readonly element: HTMLElement;
constructor(
elementRef: ElementRef,
private scrollTracker: ScrollTracker,
) {
this.element = elementRef.nativeElement;
// Wait for list rendering to complete and restore previous scroll pos
this.afterViewInit$.pipe(
delay(0)
).subscribe(() => this.restorePosition());
// Store scroll pos every 250ms
fromEvent<MouseEvent>(this.element, 'scroll').pipe(
debounceTime(250)
).subscribe(() => this.savePosition());
}
private savePosition(): void {
this.scrollTracker.saveScrollPosition(this.elementId, { position: this.element.scrollTop });
}
private restorePosition(): void {
const scrollPos = this.scrollTracker.getScrollPosition(this.elementId);
if (scrollPos !== undefined) {
this.element.scrollTo({ top: scrollPos.position });
}
}
}
Then you can simply add the directive to your lists with a unique id, i.e.:
<li-virtual-scroll scrollTracker="some-virtual-list">
...
</li-virtual-scroll>
That’s very useful, thanks for the example I will use a variation of that in a few places.
for most of my uses though the viewcache setting resolved this.
mill close this ticket off.
Scroll down the list, check the scrollPosition value on the li-virtual-scroll. For example is 16448.
Click the item to navigate to a detail view. Go back to the list view.
The position in the list has changed. Check the scrollPosition, it's now 18640.
Scroll position (and hence visible position in the list) should be retained without change when clicking through to a detail view and then back to the list view.