Using TypeScript to maintain the context of class methods as event handlers within the "this" instance

I'm facing a challenge with TypeScript Classes where I constantly need to use Function.bind() to link HTML Element events to the current instance.

class VideoAdProgressTracker extends EventDispatcher
{
    private _video:HTMLVideoElement;

    constructor(video:HTMLVideoElement)
    {
        super();
        this._video = video;
        this._video.addEventListener("timeupdate", this.handleTimeUpdateEvent);
    }

    private handleTimeUpdateEvent(event)
    {
        // Something
    }
}

It gets messy having to save the bound anonymous function repeatedly, especially when dealing with multiple events. I wish there was a simpler way to keep it bound without all the extra steps.

Any ideas for simplifying this process?

Answer №1

Utilizing arrow functions for listener methods is a convenient option:

class VideoAdProgressTracker extends EventDispatcher {
    private _video:HTMLVideoElement;

    constructor(video:HTMLVideoElement) {
        super();
        this._video = video;
        this._video.addEventListener("timeupdate", this.handleTimeUpdateEvent);
    }

    private handleTimeUpdateEvent = (event) => {
        // Something
    }
}

This approach works well, unless you intend to extend the class and customize one of these methods.
The use of arrow functions means that these are not technically methods but properties set with arrow functions, separate from the prototype chain.

For instance:

class A {
    fn1 = () => { }
    fn2() { }
}

Results in:

var A = (function () {
    function A() {
        this.fn1 = function () { };
    }
    A.prototype.fn2 = function () { };
    return A;
}());

If overriding methods is not a concern, then arrow functions can be used without issue.

To maintain using traditional methods without manually binding each one, consider:

constructor(video:HTMLVideoElement) {
    super();
    this._video = video;

    for (let key in this) {
        if (typeof this[key] === "function") {
            this[key] = this[key].bind(this);
        }
    }

    this._video.addEventListener("timeupdate", this.handleTimeUpdateEvent);
}

You can also differentiate and bind specific methods based on their names.

Answer №2

Utilizing the controller context in caching is a technique I frequently employ, especially when engaging with d3.js. This allows me to maintain connection to the callback context, typically referencing a DOM element in d3.

private onClick(): Function {
  const controller = this;
  return function(event) {
    controller.anotherClassFunction();
  };
}

private handleSecondFunction(): void {
  this.addEventListener(this.onClick());
}

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

The designated <input type=“text” maxlength=“4”> field must not include commas or periods when determining the character limit

In the input field, there are numbers and special characters like commas and dots. When calculating the maxLength of the field, I want to ignore special characters. I do not want to restrict special characters. The expected output should be: 1,234 (Total ...

Issues with Next.js and Framer Motion

My component is throwing an error related to framer-motion. What could be causing this issue? Server Error Error: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function This error occurred during page generation. Any console logs will be ...

What is the best way to automatically focus on my input when the page loads?

My Angular application has a 'slider' component that loads 3 child components utilizing ng-content. The first child component contains a form, and I am trying to focus on the first field upon page load. Despite setting up ViewChild correctly to r ...

Using the input type 'number' will result in null values instead of characters

My goal is to validate a number input field using Angular2: <input type="number" class="form-control" name="foo" id="foo" [min]="0" [max]="42" [(ngModel)]="foo" formControlName="foo"> In Chrome, everything works perfectly because it ignores ...

How to avoid property name conflicts when extending interfaces in Typescript

Is it possible to achieve something like this using TypeScript, such as renaming a property? interface Person { name: string age: number } interface Pet { age: string } interface Zoo extends Pet, Person {} How can we prevent this error from ...

Error: Unable to access the property of an undefined variable in Angular 4

Here is what I currently have in my code: <p *ngIf="model.something.satisfy"> Yes </p> <p *ngIf="!model.something.satisfy"> {{model.something.comments}} </p> The issue arises in the second line with the error message "Type ...

SlidingPane header in React disappearing behind Nav bar

Here is the code snippet from my App.js file: export class App extends React.Component { render() { return ( <BrowserRouter> <NavigationBar /> <Routes /> </BrowserRout ...

Suggestions for managing the window authentication popup in Protractor when working with Cucumber and TypeScript?

I'm a beginner with Protractor and I'm working on a script that needs to handle a window authentication pop-up when clicking on an element. I need to pass my user id and password to access the web page. Can someone guide me on how to handle this ...

Versatile functions and unique index classifications

I need help creating a versatile function that takes a type argument "T" representing an object. It should use keyof T to determine the first argument named "property". However, I am struggling with defining the type of the second argument, called "value", ...

Troubleshooting Firebase: How come my code is only accessing the initial document in my Collection?

After spending hours searching, I still can't find a solution to my problem with this code. The Firebase log file only shows: "after for each =undefinedsensor_location_1undefinedundefinedundefined " Why is it only referencing the first do ...

How is it possible to encounter a CORS issue while using axios?

I'm utilizing gin as my backend framework, and here is the code for my CORS middleware. func Cors() gin.HandlerFunc { return func(ctx *gin.Context) { method := ctx.Request.Method if method == "OPTIONS" { ctx.H ...

Trouble with Mui theme not being applied when inside a wrapper component

In my project using React with typescript and MUI version 5.4.2, I have been attempting to manage all styles in a single file by enclosing everything inside my App.tsx component. Problem: The custom MUI theme is not being applied throughout my application ...

Implementing Dynamic Updates to a Google Sheets Custom Menu using Typescript

How to Automatically Update a Custom Menu in Google Sheets using Typescript I have successfully set up the following: Dynamically Updating Custom Menu of Google Spreadsheet using Google Apps Script, a demonstration script for dynamically updating the cust ...

Is it possible to loop through each row in a table using Cypress and execute the same actions on every iteration?

I have a frontend built with html/typescript that features a table of variable length containing action buttons in one of the columns. I am looking to create a Cypress test that will click on the first button of the first row, carry out a specific task, an ...

Managing DOM elements within a Vue 3 template using Typescript

As I delve into the world of Vue 3 as a beginner, I encountered a challenge when it came to managing the DOM within Vue 3 templates. Let's take a look at the source code. MainContainer.vue <template> <div class="main-container" r ...

Creating a game of Black Jack using a prebuilt deck class

In our recent class assignment, we were tasked with implementing the ArrayBag class, which is widely available online. The next step is to utilize this class to create a Black Jack game. However, I am facing some challenges in figuring out how to proceed w ...

What am I doing incorrectly with my class implementation?

I have been working on a homework assignment that involves using classes to perform calculations for a cone. However, I am having trouble understanding how to properly utilize classes to define private members as the radius and height, and then use these ...

Is there a way to stop all HTML5 videos except for the one that I want to watch?

On my webpage, I have three HTML5 videos all on one page. My goal is to be able to pause or mute all the videos at once, except for the one that I specifically choose. Initially, I tried using an event listener on the parent div which worked well when clic ...

Tips on typing the onFocus function event parameter for a Material UI Input component

Currently, I am working on a custom dropdown using material ui components like Input and Popper. The goal is to have the popper open when the user focuses on the input field. Additionally, I am implementing this solution with TypeScript. import ClickAwayL ...

How to retrieve the default type returned by a function using a custom TypeMap

I have a function that returns a promise with a type provided by generics. const api = <Model>(url: string) => Promise<Model> Currently, I always need to set the type of the returned data. const data = await api<{id: string, name: string ...