Instance of "this" is undefined in Typescript class

After stumbling upon this code online, I decided to try implementing it in TypeScript.

However, when running the code, I encountered an error:

Uncaught TypeError: Cannot set property 'toggle' of null

@Injectable()
export class HomeUtils {
    private canvas: HTMLCanvasElement;
    private context;
    private toggle = true;

    constructor() { }

    public startNoise(canvas: HTMLCanvasElement) {
        this.canvas = canvas;
        this.context = canvas.getContext('2d');
        this.resize();
        this.loop();
    }

    private resize() {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
    }

    private loop() {
        this.toggle = false;
        if (this.toggle) {
            requestAnimationFrame(this.loop);
            return;
        }
        this.noise();
        requestAnimationFrame(this.loop);
    }

    private noise() {
        const w = this.context.canvas.width;
        const h = this.context.canvas.height;
        const idata = this.context.createImageData(w, h);
        const buffer32 = new Uint32Array(idata.data.buffer);
        const len = buffer32.length;
        let i = 0;

        for (; i < len;) {
            buffer32[i++] = ((255 * Math.random()) | 0) << 24;
        }

        this.context.putImageData(idata, 0, 0);
    }

}

Feeling confused and stuck at this point.

Answer №1

Proper handling of the this keyword is crucial in methods as they rely on the caller to correctly pass it. For instance:

this.loop() // works fine
let fn = this.loop;
fn(); // Incorrect use of this
fn.apply(undefined) // Using an undefined this

When passing the loop function to another function like requestAnimationFrame, it's essential to ensure that this is captured from the declaration context and not determined by requestAnimationFrame:

You have two options: pass an arrow function to requestAnimationFrame

private loop() {
    this.toggle = false;
    if (this.toggle) {
        requestAnimationFrame(() => this.loop());
        return;
    }
    this.noise();
    requestAnimationFrame(() => this.loop());
} 

Or you can convert the loop into an arrow function instead of a method:

private loop = () => {
    this.toggle = false;
    if (this.toggle) {
        requestAnimationFrame(this.loop);
        return;
    }
    this.noise();
    requestAnimationFrame(this.loop);
}

The second approach is preferable as it avoids creating a new function instance every time requestAnimationFrame is called. Given that this will be called frequently, opting for the second version can help minimize memory allocations.

Answer №2

Utilizing the requestAnimationFrame function is crucial in this scenario. When you pass a function that is not bound to a specific context, the loop call lacks a proper reference to this.

To rectify this issue, adjust the call as follows:

requestAnimationFrame(() => this.loop());

Unlike regular functions, arrow functions are directly bound to the correct instance of this.

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

Guide to developing a personalized useReducer with integrated decision-making and event activation

I am interested in creating a custom hook called useTextProcessor(initialText, props). This hook is designed for managing and manipulating text (string) within a React state. It utilizes useReducer to maintain a cumulative state. Here is the implementation ...

Tips for converting numerical values in a JSON object to strings within a TypeScript interface

{ "id": 13, "name": "horst", } in order to interface A { id: string; name: string; } When converting JSON data of type A to an object, I expected the conversion of id from number to string to happen automatically. However, it doesn' ...

Data loss occurs when the function malfunctions

Currently, I am working with Angular version 11. In my project, I am utilizing a function from a service to fetch data from an API and display it in a table that I created using the ng generate @angular/material:table command. Client Model export interfac ...

Utilizing directives while initiating dynamic components

I've been exploring the capabilities of dynamically creating components using the ComponentFactoryResolver. const factory = this.componentFactoryResolver.resolveComponentFactory(FooComponent); const component = this.templateRoot. ...

What is the best way to differentiate between the legend and chart when working with three separate

I have encountered an issue with my pie charts. The first chart has 10 legends displayed below it, while the second chart only has 4 legends. When I adjust the padding to accommodate the 10 legends in the first chart, the names of the 4 legends in the se ...

Craft a specialized script for manipulating the DOM

I'm currently working on a project using Angular 2. I have implemented a menu that should be able to close when a button is clicked. Instead of using a component for the menu, I want to keep it lightweight by placing it outside of Angular. However, I ...

When transitioning from component to page, the HTTP request fails to execute

I have created a dashboard with a component called userInfo on the homepage. This component maps through all users and displays their information. Each user has a display button next to them, which leads to the userDisplay page where the selected user&apos ...

Mastering the proper usage of the import statement - a guide to seamless integration

I'm excited to experiment with the npm package called camera-capture, which allows me to capture videos from my webcam. As someone who is new to both npm and typescript, I'm a bit unsure about how to properly test it. Here's what I've ...

Exploring the attributes of a record through a combination of string template types

I'm utilizing a string template type to denote ids with a significant prefix, such as dta-t-${string} where dta-t- encodes certain details about the entity. I have various record types that are indexed by unions of string templates: type ActivityTempl ...

What is the best way to retrieve matching values based on IDs from an imported table?

How can I retrieve values that match on ID with another imported table? My goal is to import bank details from another table using the ID and display it alongside the companyName that shares the same ID with the bank details. I've attempted several o ...

Converting Getters into JSON

I am working with a sequelize model named User that has a getter field: public get isExternalUser(): boolean { return this.externalLogins.length > 0; } After fetching the User from the database, I noticed in the debugger that the isExternalUser prop ...

Is it possible to convert a DynamoDB AttributeMap type into an interface?

Assume I define a TypeScript interface like this: interface IPerson { id: string, name: string } If I perform a table scan on the 'persons' table in DynamoDB, my goal is to achieve the following: const client = new AWS.DynamoDB.Documen ...

Angular Error cli command Error: In order to proceed, please provide a command. To see a list of available commands, use '--help'

When I run any command with Angular CLI, I encounter an error. To resolve this issue, I attempted to uninstall and reinstall it by running the following commands: npm uninstall -g @angular/cli npm install -g @angular/cli However, the problem persists an ...

Angular 5 is throwing an error that says: "There is a TypeError and it cannot read the property 'nativeElement' because it

Being aware that I may not be the first to inquire about this issue, I find myself working on an Angular 5 application where I need to programmatically open an accordion. Everything seems to function as expected in stackblitz, but unfortunately, I am enco ...

Exploring the compatibility of Next.js with jest for utilizing third-party ESM npm packages

Caught between the proverbial rock and a hard place. My app was built using: t3-stack: v6.2.1 - T3 stack Next.js: v12.3.1 jest: v29.3.1 Followed Next.js documentation for setting up jest with Rust Compiler at https://nextjs.org/docs/testing#setting-up-j ...

What could be the reason for the 'tsc' command not functioning in the Git Bash terminal but working perfectly in the command prompt?

I recently installed TypeScript globally on my machine, but I am facing an issue while trying to use it in the git bash terminal. Whenever I run tsc -v, I encounter the following error: C:\Users\itupe\AppData\Roaming\npm/node: l ...

How to Pass Data as an Empty Array in Angular 6

After successfully implementing a search function that filters names from an array based on user input, I encountered an issue when trying to make the searchData dynamic by fetching it from a Firebase database: getArray(): void { this.afDatabase.list( ...

Experiencing Typescript errors solely when running on GitHub Actions

I've been working on a React+Vite project with the Dockerfile below. Everything runs smoothly when I execute it locally, but I encounter errors like Cannot find module '@/components/ui/Button' or its corresponding type declarations and error ...

Angular progress bar with dynamic behavior during asynchronous start and stop

Currently, I am facing an issue with the progress bar functionality while utilizing the ng-bootstrap module. The scenario involves a dropdown menu with multiple options, and my desired behavior includes: The ability to start/stop the progress bar indepen ...

I am encountering an issue with an undefined variable called "stripe" in my Angular project, despite the fact

Within my stripecreditcardcomponent.html file: <script src="https://js.stripe.com/v3/"></script> <script type="text/javascript"> const payment = Stripe('removed secret key'); const formElements = paymen ...