Error: TypeScript encountered an issue while attempting to access a property that is undefined

I just can't seem to figure out what's missing here. Running the following code gives me this error:

Uncaught TypeError: Cannot read property 'addEventListener' of undefined"


        class Editor{
            public context: CanvasRenderingContext2D;
            constructor( public canvas: HTMLCanvasElement){
                this.context = this.canvas.getContext("2d");
                this.canvas.addEventListener("mousedown", this.handleMouseDown);
            }
            handleMouseDown(ev: MouseEvent){
                this.canvas.addEventListener("mousemove", this.handleMouseMove);
            }
            handleMouseMove(ev: MouseEvent){
                console.log(ev);
                console.log(ev.target);
            }
        }

        let mapEditor = new Editor(<HTMLCanvasElement>document.getElementById("map-editor"));
    

But when I try a different approach, it works fine:


        let cnv = document.getElementById("map-editor") as HTMLCanvasElement;
        cnv.addEventListener("mousedown", handleMouseDown);

        function handleMouseDown(ev: MouseEvent){
            ev.target.addEventListener("mousemove", handleMouseMove);
            handleMouseMove(ev);
        };

        function handleMouseMove(ev: MouseEvent){
            console.log(ev);
            console.log(ev.target);
        };
    

I've rearranged things and searched for solutions, but the event still won't trigger. Am I overlooking something important in the language?

Edit: After some digging, I believe that the "this" keyword loses its reference to the class instance when the mousedown event is triggered, causing this.canvas to be undefined. I plan to explore alternative ways of binding methods with events.

For further explanation, check out this link: 'this'-in-TypeScript

Answer №1

The issue stems from the dynamic environment. The Editor class attaches an event listener to the canvas, specifically for "mousedown". However, when the event triggers and the method is invoked, 'this' points to the canvas element instead of the encompassing class. Consequently, attempting to access a member like 'canvas' yields an undefined result. To resolve this quandary, as recommended by Alex, it is advised to bind 'this' lexically to the class instance during method invocation using the fat arrow syntax, demonstrated below:

myClass.member.addEventListener("event", (e) => myClass.handleEvent(e));

Presented here is my implementation for the problem:

class Editor{
    public context: CanvasRenderingContext2D;
    public rect: ClientRect;
    constructor( public canvas: HTMLCanvasElement){
        this.context = this.canvas.getContext("2d");
        this.rect = this.canvas.getBoundingClientRect();
        this.canvas.addEventListener("mousedown", (ev) => this.handleMouseDown(ev));
    }
    handleMouseDown(ev: MouseEvent){
        console.log(this);
        this.canvas.addEventListener("mousemove", (ev) => this.handleMouseMove);
    }
    handleMouseMove(ev: MouseEvent){
        console.log(this);
    }
    getGridCoordinate(x: number, y: number){
    //This function should accurately determine the grid coordinate.
        return {
            x: x - this.rect.left,
            y: y - this.rect.top
        };
    }
}

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

What strategies can be implemented to maximize the effectiveness of Office ribbon commands within an AngularJS application?

Currently, I have developed an Office add-in using AngularJS (version 1.4) and ASP.NET MVC 4.5. The Angular controller and service JS files contain a significant amount of functionality that has already been implemented. Lately, I have been exploring the ...

Products failing to appear in shopping cart

I'm facing an issue with my React Redux Cart setup where items are added to the cart state using the addItem action, but they do not appear on the Cart page. Challenge: After adding items to the cart through the addItem action, I can see the state u ...

How can I achieve the quickest image loading speed with JavaScript?

If I have a large ecommerce website with 15,000 image elements that need to be added to the HTML, what is the best approach using JavaScript to optimize efficiency and enhance user experience? ...

Is there a way to deactivate middleware in Node, Express, and Mocha?

My application features a hello world app structured as follows: let clientAuthMiddleware = () => (req, res, next) => { if (!req.client.authorized) { return res.status(401).send('Invalid client certificate authentication.'); } ret ...

The functionality of closing the image on a model popup is not functioning properly following a postback

I am encountering an issue with my ajax modelpopup extender in my webform. The CancelControlID is set to an image called imgClose. When I click on imgClose after the popup has been displayed, it successfully closes the popup. However, if I click on any co ...

Is there a way to identify when a Tween.js animation has completed?

Is there a completed or finished event available when using this code for animating the camera in a scene with tween.js? tween : function (target){ var position = camera.position; var tween = new TWEEN.Tween(p ...

Displaying multiple categories of articles on a single page with Node.js

Seeking a solution to limit the number of posts displayed for each category using a .limit() function, but uncertain on how to proceed. Currently utilizing Mongoose and Express in my code setup. The existing code snippet is outlined below: router.get(&a ...

Improve the Popup to seamlessly elevate

In my project, I have implemented a pop-up dialog box that rises up from the left bottom corner as the user scrolls down the page. You can view it live at this link- However, I am facing an issue where the initial lift up of the dialog box is not smooth, ...

It is impossible to add a new element between two existing elements that share the same parent

I'm attempting to place an <hr> tag between the first and second .field-container. Because they have the same parent, I thought using element1.parentNode.insertBefore(element2, ...) would be the solution. However, it is not working as expected a ...

Incorporate Angular frontend into current website or project

I've successfully built a website using bootstrap, but now I'm looking to integrate Angular in order to transform it into a single page application. The goal is that when a user clicks on a link, only the necessary content will be loaded from the ...

Change TypeScript React calculator button to a different type

I am currently troubleshooting my TypeScript conversion for this calculator application. I defined a type called ButtonProps, but I am uncertain about setting the handleClick or children to anything other than 'any'. Furthermore, ...

Changing Ionic back button to a specific route/view

Coming from view1, I navigate to $state.go('app.view3'); Now that I'm in my view3.html, how can I configure the back button to direct to view2 when clicked by the user? ...

What is preventing me from using javascript setInterval with a function in a separate external file?

Everything is running smoothly with this code snippet...an alert pops up every 10 seconds <script type='text/javascript'> function letsTest(){ alert("it works"); } var uptimeId = window.setInterval(letsTest, 10000); < ...

Generating a clickable hyperlink within a b-table cell using Vue Bootstrap

When using the b-table component, I encounter an issue. <b-table responsive hover :items="myItems" :fields="myField"> My backend returns a URL within my items, and I want to display it in my template. <template slo ...

I'm curious if there is an eslint rule specifically designed to identify and flag any unnecessary spaces between a block comment and the function or

Can anyone help me find a solution to prevent the following issue: /** * This is a comment */ function foo() { ... } I need it to be corrected and formatted like this: /** * This is a comment */ function foo() { ... } ...

Modify the script to manage the closing of one modal while simultaneously opening a different one

Looking for help with adjusting a script to close the current Modal and open a new one on button click, all while utilizing a reusable modal framework loading PartialViews. I feel like I'm overlooking something crucial but can't quite figure out ...

NavLinkButton - add style when active or selected

I'm working with a list of NavLinks: const users = Array.from(Array(5).keys()).map((key) => ({ id: key, name: `User ${key}`, })); <List> {users.map((user) => { return ( <ListItem disablePadding key={user.id}> ...

AngularJS form buttons are currently not active or validated

In my AngularJS form, the default data pulled from scope should enable validation and allow submission. However, I am encountering an issue where the button remains disabled until data is entered in the input field. Here is the code snippet: <div ng-co ...

Problem with opening the keyboard feature in an Ionic app

Hello everyone, I'm relatively new to Ionic development and I've been trying to integrate a keyboard plugin into my application that opens from the footer and focuses on input fields for entering values. Here is the link to the plugin I used: ht ...

Default functionality of Typescript paths imports fails to operate properly

Can anyone help me figure out how to set up default imports in my .ts files using the paths specified in my tsconfig.base.json? I have this file defined as default in the File Type > Typescript Config. https://i.sstatic.net/LvBGV.png The import statem ...