Sending an array of functions to the onClick event of a button

Having difficulty with TypeScript/JavaScript

Currently working with an array of functions like this

private listeners: ((name: string) => void)[] = [];

Successfully adding functions to the array within another function.

Now looking to trigger those functions on button press

button.onclick = function(){
   this.listeners.forEach((callback) => callback(username));
}

When attempting to execute this code, nothing happens. It appears to be due to lack of recognition of listeners.

Next attempt was

button.onclick = function(listeners){
       listeners.forEach((callback) => callback(username));
}

Now encountering tsc error

error TS2339: Property 'forEach' does not exist on type 'MouseEvent'.

Suspecting a missing type declaration, but unsure how to specify that this array consists of functions of type

((name: string) => void)[] = [];

If anyone has a quick workaround, it would be greatly appreciated. And just to address any potential questions: I can confirm that the add function did increase the size of the listeners array at least (it's reassuring - :D).

Answer №1

Ensuring that 'this' remains pointing to the current class instance is crucial when defining your onclick handler. One way to achieve this is by structuring it as follows:

private handleOnClick(event)
{
    this.callbacks.forEach((func) => func(parameter));
}

//Later on in the code 
button.onclick = (event) => this.handleOnClick(event);

Answer №2

The main issue you're facing is that the reference to this is not pointing to the context you expect. Instead, this is referring to the context of the MouseEvent in your click handler.

One way to solve this problem is by using Function.prototype.bind().

Replace

button.onclick = function(){ 
   this.listeners.forEach((callback) => callback(username));
}

With

button.onclick = function(){ 
   this.listeners.forEach((callback) => callback(username));
}.bind(this);

Here's a simple explanation:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

Answer №3

An advanced method to tackle your problem is to avoid using onclick and instead utilize addEventListener. You can take advantage of a lesser-known technique by passing an object with a handleEvent method to addEventListener, eliminating all concerns with this:

class Bar {

  private observers: ((name: string) => void)[] = [];

  constructor(button) {
    button.addEventListener('click', this);
  }

  handleEvent(event) {
    // validate event type
    this.observers.forEach(callback => callback(username));
  }

}

const new Bar(document.getElementById('myButton'));

Answer №4

Appreciate the responses!

I realized that directly adding a function wouldn't work because it's an Eventhandler function, which operates somewhere else in the code but not where I initially defined it.

So, I switched to using `addeventhandler` and defined a function within my function. I then called a new function for the Eventhandler, which in turn calls the function it should execute. #funcception :D

let triggerOnClick = () => {
        let username = tf_name.value;
        this.listeners.forEach((callback) => callback(username));
    };

    btn_enter.addEventListener("click", () => {
        triggerOnClick();
    });

And voila, that code is now functioning perfectly :)

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

Component not appearing in Storybook during rendering

I'm trying to incorporate the MUI Button Component into my storybook and then dynamically change MUI attributes like variant, color, and disabled status directly from the storybook. While I was successful in doing this with a simple plain HTML button, ...

The date format is malfunctioning -> Error: The date provided is not valid

My goal is to convert the date format from 2022-01-17T21:36:04.000Z to January 18th using the npm package, dateFormat. I found success with the following code snippet: const date = dateFormat("2022-01-17T21:36:04.000Z", "mmmm dS"); However, when trying t ...

What causes a delay in the start of a child process in Node.js?

I am in the process of developing a global node command line program that can execute any console command I provide it with in a new console window, whether on a Windows or Unix system. The goal is for the program to exit after it spawns its process so tha ...

How do I incorporate global typings when adding type definitions to an npm module?

Suppose I create a node module called m. Later on, I decide to enhance it with Typescript typings. Luckily, the module only exports a single function, so the m.d.ts file is as follows: /// <reference path="./typings/globals/node/index.d.ts" /> decl ...

Refreshing CSS-Element-Queries following an ajax request

I’ve been utilizing css-element-queries from the https://github.com/marcj/css-element-queries repository to tailor styles based on an element's dimensions. However, I encountered an issue when dynamically adding elements via ajax calls. The new elem ...

Tips for correctly displaying diacritics with Webpack and Typescript

While working on my project, I encountered an issue with diacritics marks (such as German or Polish characters) when using Webpack with Typescript. Unfortunately, the problem arises when trying to display these marks in the console or on a webpage. It seem ...

Ways to create a looping mechanism with specified number restrictions and limitations

Can anyone assist me with this problem? I am looking to create a "looping" effect similar to the image provided. What is the logic behind this repetition? Thank you in advance for your help! Here is an example output: ...

Tips for Designing a Custom Footer Layout for KoGrid

Is it possible to create a footer template for a koGrid that displays the sum of a column? gridOptions : { displaySelectionCheckbox: false, data: items, // selectedItems: self.selectedItems, multiSelect: false, ena ...

Increase the dimensions of the jQuery modal confirmation box

I am working on a jQuery confirmation dialog that displays some details for the user. My goal is to have the dialog adjust its dimensions after the user clicks "YES" to show a smaller text like "Please wait...". How can I dynamically change the size of the ...

Is there a way to have multiple app.post functions for the same route using express()?

I'm currently exploring the idea of incorporating multiple app.post functions in my project. Specifically, I have a client-side JavaScript function that sends a request to the server-side JavaScript to add content to a database using the app.post func ...

Executing mathematical calculations within a JavaScript object

Can an equation be executed inside an object? For instance: var taxes = { gst: '0.10', }; var prices = { first_key: '437.95', total_key: parseFloat(prices.first_key * taxes.gst).toFixed(2), ....... }, }; Or do I n ...

"Troubleshooting: State array in ReactJS/NextJS not rendering correctly following setState

I am facing challenges with rendering my objects using .map() within React / NextJS. Within my code, I have a function where I retrieve images from Firebase Cloud Storage as shown below: getImages = () => { let firebase = loadFirebase() ...

Parsing error: Unforeseen token encountered. Consider adding a supplementary loader to manage the output of these loaders

Could someone please break down this syntax message?.length === 1 and show me how to convert it into standard JavaScript? https://i.stack.imgur.com/20Ui6.png I am encountering an error when trying to use a Vue.js component that I downloaded from another ...

I am confused about the process of mounting components

Utilizing pattern container/representational components, I have a CardContainer component that retrieves data from a server and passes it to a Card component. Container Component: class CardContainer extends Component { state = { 'ca ...

I am unable to integrate Autoprefixer into an Express project

I am having trouble adding Autoprefixers to the postcssmiddleware, as mentioned in the documentation here I also attempted using express-autoprefixers but still cannot see the vendors in my dest or public folder. You can find a link to my repository (node ...

What is the best way to extract raw data from a kendo dataSource?

After fetching data for my Kendo grid from the backend and populating it in the alignedProcessesToRiskGridOptions, I noticed that while the data is displayed in the grid, I also need access to the raw data for additional logic. Is there a way to retrieve d ...

Accessing weather information in React with Ajax

Utilizing the Open Weather Map current weather data API, my goal is to integrate real-time weather data retrieval into my React.js application using ajax. My aim is to extract the current temperature for a specified city and display this value within my co ...

Why Mixin Class inference is not supported in Typescript

I encountered an issue in my code: The error message 'Property 'debug' does not exist on type 'HardToDebugUser'.' was displayed. It seems like Typescript failed to infer the mixin class correctly. Can you please explain this t ...

When a React Native TextInput is focused, it restricts the ability to press other child components

Issue with Nested TextInput component affecting onPress function of other components. Press only works when the TextInput is not in focus. React Native Version : 0.66.3 Here's the code snippet: export const Component = (props): JSX.Element { const ...

In Typescript, which kind of event is suitable for MouseEvent<HTMLDivElement>?

My goal is to close the modal when clicking outside the div element. Take a look at my code below. // The onClose function is a setState(false) function. import { useRef, useEffect } from 'hooks' import { MouseEvent } from 'react' imp ...