Angular2 with TypeScript: Issue with unchanged variable

I've noticed that my variable isInfinitiveScrollLoaderEnabled doesn't seem to change when I reach the bottom of the page. However, if I place it at the beginning of the ngOnInit method, it does change successfully.

What could be causing this issue?

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

Answer №1

Angular offers a convenient method for listening to events on the 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;
    }
  }
}

To implement an imperative approach, refer to Programmatically (un)register to event with Angular 2

Answer №2

To successfully handle the onscroll callback within an Angular2 environment, utilize the power of the NgZone class to ensure that the event executes in the appropriate context:

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

Check out this plunkr demonstration for reference: https://plnkr.co/edit/PI5wbMnWEY56EiB4wGEH?p=preview.

The reason behind using the window object outside of Angular2's scope...

Answer №3

In this comprehensive explanation, Günter Zöchbauer's answer has been hailed as exceptional (with upvotes received). Let me touch upon some key points:

Angular2's Zone library is noted for extensively patching various APIs, particularly the event listener APIs. However, it does not extend to the window/element on<EVENT> properties, possibly due to their outdated and discouraged nature.

For seamless functionality, utilizing the addEventListener API is strongly recommended.

Illustrated below is an 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;
      }
    });
  }
}

Additionally, for those keen on abstracting DOM elements for compatibility with server rendering or mobile frameworks such as NativeScript / ReactNative, alternative options can be explored:

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

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

Alternatively,

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

This approach appears most declarative in my opinion.

Both alternatives align with Günter Zöchbauer's guidance.

While navigating these rendering considerations may seem unfamiliar within your codebase, the choice ultimately lies with you and should prove satisfactory.

Regardless of your decision, it is advisable to steer clear of using the this.ngZone.run() option, as it tends to evoke unfavorable comparisons to the days of $scope.$apply(), although admittedly less severe.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble containerizing a Vite React-Typescript project with Docker

I'm currently in the process of dockerizing a Vite React-Typescript boilerplate setup, but I'm encountering difficulties connecting to the container. Here's how I installed the vite-react-typescript boilerplate: npm init vite@latest vite-d ...

Executing Protractor test in Firefox with pop-up clearing

When running my protractor End to end test on my angular app, I encountered an issue where I couldn't clear a pop up using the ENTER or ESCAPE keys. await element(by.xpath("//*")).sendKeys(protractor.Key.ENTER); or await element(by.xpath(& ...

In a functional component in Typescript, what data type should be used for a parameter that accepts an array of objects?

const FormData = ({ dataArray }: object[]): JSX.Element => { console.log("Array of Objects",dataArray) //This is a large form component.... }); The dataArray contains multiple objects, how can I specify a specific type for these components ...

Is there a way for me to view the output of my TypeScript code in an HTML document?

This is my HTML *all the code has been modified <div class="testCenter"> <h1>{{changed()}}</h1> </div> This is my .ts code I am unsure about the functionality of the changed() function import { Component, OnInit } f ...

Having difficulty authenticating a JWT token in my Nextjs application

Help required with verifying a JWT token in Nextjs as I'm encountering the following error: TypeError: Right-hand side of 'instanceof' is not an object See below for the code I am currently using: useEffect(() => { let token = localS ...

Typescript version 2 is facing difficulties in resolving an external node module

Lately, I've been experimenting with prototyping using koa and Typescript 2.0. In my simple project, I've configured the tsconfig.json file like this: { "compilerOptions": { "outDir": "./bin/", "sourceMap": true, "no ...

There are currently no loaders set up to handle this file at the moment

I am currently working on a TypeScript(TS) React project that contains all of my React components. I am in the process of converting this project into an NPM package so that it can be used in other separate React projects. To address the issue of .css and ...

How can I redirect a remote image URL to a local folder during development?

Currently, I am pulling image URLs from a database that was dumped from the production server. An example of one of these URLs is https://example.com/imageStorage/photo.jpg. These URLs are then used to display images in HTML templates using the following f ...

Application: The initialization event in the electron app is not being triggered

I am facing an issue while trying to run my electron app with TypeScript and webpack. I have a main.ts file along with the compiled main.js file. To troubleshoot, I made some edits to the main.js file to verify if the "ready" function is being called. ...

What is the best way to position a material icon to the right of an input field?

Currently, I am using a mat auto complete text box with a search icon that is aligned to the left of the input. I am looking to align this search icon to the right instead. Can anyone provide assistance on how to achieve this? <mat-form-field floatLa ...

Setting innerHTML does not affect the content of an SVG element

I am currently working on an Angular 7 application and I need to dynamically update the text value based on a dropdown selection. For example, if the id of the text element is 10, then I want to change the text from 'hi' to 'hello'. T ...

Error in Angular 7: ActivatedRoute paramId returns null value

On page load, I am trying to subscribe to my paramsID, but when I use console.log(), it returns null. I am currently working with Angular 7. Here is my TypeScript code: import { Component, OnInit } from '@angular/core'; import { Activat ...

Problem with Primeng multiselect not displaying selected values

I am currently facing an issue with populating options on a p-multiSelect element. The HTML code in question is: <p-multiSelect name="ambits" [options]="scopes$ | async"> </p-multiSelect> The variable scopes$ is defined as follows: publ ...

Setting default properties for Ionic Components can be achieved by following this guide

Is it possible to set default properties for Ionic components when used with Angular 11? For example, instead of repeating the position for every label, can a meaningful default be enforced for the entire application? <ion-label position="floating ...

In what way can TS uniquely handle each element of an array as the key of an object?

I am struggling with an object that I need to have keys representing every item in the array, each linked to a value of any. Can anyone provide guidance on how to achieve this? Unfortunately, I couldn't find a solution. Here is an example for refere ...

Error: The 'Store' property is not found in the '{}' type but is needed in the 'Readonly<Istore>' type. TS2741

Can you assist me in resolving this issue? I am attempting to pass my store as props to the component, but I keep encountering the following error: Type error: Property 'Store' is missing in type '{}' but required in type 'Readon ...

How can you retrieve the keys of an object that conforms to an interface?

In the following demonstration, we have two objects - KEYS and KEYS2. When importing KEYS in index.ts, autocomplete suggestions are available for K1 and K2 because KEYS does not adhere to an interface. On the other hand, with KEYS2, autocomplete is not pr ...

Typescript: Defining a universal interface for a React component or HTML element along with its corresponding properties

I am in the process of creating a unique wrapper interface. In my search, I have come across some intriguing types: Imagine Bar as a React component that requires props of type BarProps. Consider Z as the interface that serves as a representation for any ...

Utilizing the "as" keyword for type assertion in a freshly created react application using create-react-app leads to the error message `Parsing error: Unexpected token, expected ";"`

After creating a new CRA project using yarn create react-app my-app --template typescript, I encountered an error when trying to run the development server with yarn start: src/App.tsx Line 5:24: Parsing error: Unexpected token, expected ";" ...

What is the process of implementing a particular FormControl from a FormArray in my HTML file?

My FormArray initialization code is as follows: this.contents.forEach(content=> { this.formArray.push( new FormControl(content.text, Validators.required)); }); Now, I am trying to associate a specific FormControl with my textarea by using i ...