Tracking scroll position and notifying other components about it
I think the easiest way is each interested component listening to the scroll event.
@Component({ ... // alternative to `@HostListener(...)` // host: {'(window:scroll)': 'doSomething($event)'} }) class SomeComponent { @HostListener('window:scroll', ['$event']) doSomething(event) { // console.debug("Scroll Event", document.body.scrollTop); // see András Szepesházi's comment below console.debug("Scroll Event", window.pageYOffset ); } }
Hint:
bootstrap(MyComponent, [ provide(PLATFORM_DIRECTIVES, {useValue: [TrackScrollDirective], multi:true})]);
makes the directive universal without adding it to every components directive: [...]
list.
I was forced to solve this differently because I needed to watch several scrolling elements on the window. I created a directive to watch the scroll position on an element:
@Directive({ selector: '[scroll]'})export class ScrollDir { @Output() setScroll = new EventEmitter(); private scroll: number; constructor(private el: ElementRef) { } @HostListener('scroll', ['$event']) scrollIt() { this.scroll = event.srcElement.scrollTop } reset() { this.el.nativeElement.scrollTop = this.scroll }}
Then on any any component containing a scroll element that needed this element I could @ViewChild
the directive like this:
@Component({ selector: 'parent', template: ` <div class="container" scroll> // *ngFor=""... </div> `})export class ParentComp implements AfterViewChecked { @ViewChild(ScrollDir) scroll: ScrollDir; ngAfterViewChecked() { this.scroll.reset() }}
Look at the source to ScrollService, as part of the angular documentation project.
The way they get the position is fromEvent(window, 'scroll')
You can then do something like this in a global service you inject into your component:
public readonly windowScroll$ = fromEvent(window, 'scroll').pipe(map(x => window.scrollY), startWith(0), distinctUntilChanged(), shareReplay(1));
The startWith(0)
is needed because you may not get a scroll event until you actually scroll. You can add debouncing if needed.