2

It looks my variable's isInfinitiveScrollLoaderEnabled value does not change when reaching bottom of page. If I put it at the beginning ngOnInit method, it changes successfully.

What could be wrong?

export class SomeClass {
  private isInfinitiveScrollLoaderEnabled: boolean;

  constructor() {
    this.isInfinitiveScrollLoaderEnabled = false;
  }

  ngOnInit() {
    window.onscroll = (event) => {
      if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
        console.log('Bottom of page');
        this.isInfinitiveScrollLoaderEnabled = true;
      }
    };
  }
}

3 Answers 3

2

Angular provides an easy way to listen to events on window or document:

@Component({
  selector: 'some-class',
  // alternative to @HostListener below
  // host: {'(window:scroll)':'onScroll($event')},
  ...
})
export class SomeClass {
  private isInfinitiveScrollLoaderEnabled: boolean;

  constructor() {
    this.isInfinitiveScrollLoaderEnabled = false;
  }

  @HostListener('window:scroll', ['$event'])
  onScroll(event) {
    if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
      console.log('Bottom of page');
      this.isInfinitiveScrollLoaderEnabled = true;
    }
  }
}

For an imperative way see Programmatically (un)register to event with Angular 2

Sign up to request clarification or add additional context in comments.

Comments

2

You need leverage the NgZone class to execute the onscroll callback in the context of Angular2 when the event is triggered:

export class SomeClass {
  private isInfinitiveScrollLoaderEnabled: boolean;

  constructor(private ngZone: NgZone) {
    this.isInfinitiveScrollLoaderEnabled = false;
  }

  ngOnInit() {
    window.onscroll = (event) => {
      if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
        console.log('Bottom of page');
        this.ngZone.run(() => {
          this.isInfinitiveScrollLoaderEnabled = true;
        });
      }
    };
  }
}

See this plunkr: https://plnkr.co/edit/PI5wbMnWEY56EiB4wGEH?p=preview.

It's because the window object is instantiated outside Angular2...

Comments

1

Günter Zöchbauer's answer is perfect (upvoted). I want to explain a bit about it:

The Zone library that Angular2 uses internally monkey patches a lot of APIs, including the event listener APIs. But this does not include the window/element on<EVENT> properties, maybe because they are considered old and discouraged.

But if you use the addEventListener API, this should work just fine.

Example:

export class SomeClass {
  private isInfinitiveScrollLoaderEnabled: boolean;

  constructor(private ngZone: NgZone) {
    this.isInfinitiveScrollLoaderEnabled = false;
  }

  ngOnInit() {
    window.addEventListener('scroll', (event) => {
      if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
        console.log('Bottom of page');
        this.isInfinitiveScrollLoaderEnabled = true;
      }
    });
  }
}

Of course if you can about abstracting away the DOM for use with server rendering or mobile frameworks like NativeScript / ReactNative, you can go for the other valid options

import {DOM} from 'angular2/platform/common_dom.dart';

DOM
    .getGlobalEventTarget('window')
    .addEventListener('message', function, false);

Or

@HostListener('window:scroll', ['$event'])`

which looks the most declarative to me.

Both as Günter Zöchbauer mentioned.

If you don't care about these rendering considerations, they might look foreign or so in your code. It's your call either way and should be fine.

Whatever you choose, I'd stay away from the this.ngZone.run() option, because it brings bad memories from the days of $scope.$apply(), although admittedly it's not as bad.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.