12

I'm using @HostListener('window:scroll', []) in Angular 4 app in order to add additional class to the header on scrolling. It works fine in Chrome but I noticed that in Firefox 54.0 (I think it's the last current version) the class is not added, it does not execute onWindowScroll() method at all. What can be the reason?

Here is a part of the code and a Plunker Demo (which by the way, also works fine in Chrome but not in Mozilla):

public isScrolled = false;
constructor(@Inject(DOCUMENT) private document: any) {}
@HostListener('window:scroll', [])
onWindowScroll() {
    const number = this.document.body.scrollTop;
    if (number > 150) {
        this.isScrolled = true;
    } else if (this.isScrolled && number < 10) {
        this.isScrolled = false;
    }
}


Any help would be much appreciated.

Petya Naumova
  • 727
  • 2
  • 11
  • 23

4 Answers4

22

try this:

@HostListener('window:scroll', ['$event'])
onWindowScroll($event) {
    console.log("scrolling...");
}

I prefer this:

import { fromEvent } from "rxjs";

...

this.eventSubscription = fromEvent(window, "scroll").subscribe(e => {
    this.onWindowScroll();
});
Robouste
  • 3,020
  • 4
  • 33
  • 55
Avi
  • 1,924
  • 3
  • 17
  • 31
  • Thank you for your suggestions. I tried both - the first one didn't make any difference in Firefox, the second one though - that one with the Observable made the onWindowScroll event to be fired - "Scrolling.." is logged in the console. But still does not apply the class 'scrolled' to the header. I have to read more about Observables to think about a way for fixing that. – Petya Naumova Jun 27 '17 at 10:01
11

I did face the same issue and resolved it by using window.scrollY rather than using this.document.body.scrollTop to make it work in Mozila Firefox. I know it is strange but it works.

Rishabh
  • 126
  • 2
10

How i solved this

Works perfectly on Firefox, chrome and other browsers

Concept: You can listen to the properties of scrolling element that is body for now if you don't have any other scrolling element

@HostListener('window:scroll', ['$event']) onWindowScroll(e) {
    console.log(e.target['scrollingElement'].scrollTop)

    // Your Code Here

  }
Nishant Singh
  • 1,016
  • 12
  • 15
  • Parameter 'e' implicitly has an 'any' type. – Mohammad Fareed Jan 29 '20 at 14:27
  • You can always define it's type onWindowScroll(e:Event) for reference check here what type Event Refers to https://developer.mozilla.org/en-US/docs/Web/API/Event – Nishant Singh Apr 06 '20 at 07:28
  • this should be the answer. – Gel Oct 02 '20 at 12:55
  • Trying without success. Do we have to bind onto the outermost div like `(scroll)="onWindowScroll($event)"` should the template is a component within the root component? – Deepak D Dec 04 '20 at 04:57
  • You need to attach the scroll event to whatever element is scrollable & fits to your purpose. If you are looking for scroll on body element then event on body other wise on the element for which you want to detect scroll. – Nishant Singh Dec 05 '20 at 05:37
8

This Angular directive will work in both Chrome and Firefox:

import { Directive, Output, EventEmitter, HostListener, ElementRef, OnDestroy 
} from '@angular/core';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/observable/fromEvent';

@Directive({
  selector: '[scroll]'
})
export class ScrollEventDirective implements OnDestroy {
  @Output() scrollPosition: EventEmitter<number> = new EventEmitter<number>
  ();

  private scrollEvent$;

  constructor(private el: ElementRef) {
    this.scrollEvent$ = Observable.fromEvent(this.el.nativeElement, 
    'scroll').subscribe((e: any) => {
      this.scrollPosition.emit(e.target.scrollTop);
    });
  }

  ngOnDestroy() {
    this.scrollEvent$.unsubscribe();
  }
}

Using the directive on a DIV element:

<div scroll (scrollPosition)="scrollChanged($event)">...</div>
  • Update: RxJs 6+ https://stackoverflow.com/questions/50571550/this-property-fromevent-does-not-exist-on-type-typeof-observable-angular-6 – Pavankumar Shukla Jan 29 '19 at 10:49