Tracking scroll position and notifying other components about it Tracking scroll position and notifying other components about it angular angular

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 );    }  }

plunker

Plunker using @HostListener()

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.