Issue arises when trying to set object members using a callback function in Typescript

I am facing a peculiar issue that I have yet to unravel. My goal is to display a textbox component in Angular 2, where you can input a message, specify a button label, and define a callback function that will be triggered upon button click.

Below is the code for my component:

@Component({
  selector: 'text-box',
  templateUrl: './textbox.component.html',
  styleUrls: ['./textbox.component.styl']
})
export default class TextBoxComponent implements AfterViewInit {
  content: String;
  btnCaption: String;
  callback: () => void;

  constructor(@Inject(TextBoxService) private service: TextBoxService) {
  }

  ngAfterViewInit(): void {
    this.service.init(this.show);
  }

  public show(message: String, btnCaption: String, callback: () => void) {
    this.content = message;
    this.btnCaption = btnCaption;
    this.callback = callback;
    // (1)
    // set opacity 1
  }

  public btnOnClick() {
    // (2)
    this.callback();
    this.dismiss();
  }

  public dismiss() {
    // set opacity 0
  }
}

Since components are Singletons and cannot be directly injected, invoking show() on the component from an external source is not straightforward. Therefore, I implemented a service and stored a reference to the method within it (refer to the component's ngAfterViewInit() method):

@Injectable()
export default class TextBoxService {
  private showCallback: (m: String, b: String, c: () => void) => void;

  public init(showCallback: (m: String, b: String, c: () => void) => void) {
    this.showCallback = showCallback;
  }

  public show(message: String, btnCaption: String, callback: () => void) {
    this.showCallback(message, btnCaption, callback);
  }
}

The service is invoked by another service in the following manner:

this.textBoxService.show(
  'Do you wish to apply for a loan?',
  'Yes', () => {
    target.activate();
    this.activatedEvents.set(event, target);
    this.inputService.loanInput.amount = target.getPrice() - target.getLiquidFunds();
    this.inputService.loanInput.startDate = date;
  });

However, when the button above is clicked, the text does not update, and the listener attached to the button raises an error saying

this.callback() is not a function
. Upon debugging (by adding console.log statements at (1) and (2) in the component), I discovered that both methods are being called correctly. At point (1), the members content, btnCaption, and callback are appropriately assigned, but at point (2), these members are undefined!

I attempted switching from fat arrow syntax to function() syntax without success. Even hard-coding the string inside show() did not resolve the issue of it being undefined during button click.

It appears that there might be two different objects accessed at points (1) and (2). I am puzzled as to what could be causing this behavior. Any suggestions?

Answer №1

To ensure that class prototype methods can be passed as callbacks by design (like in this.service.init(this.show)), it is recommended to define them as arrow class properties:

public show = (message: String, btnCaption: String, callback: () => void) => { ... };

Another option is to bind them on class construction:

constructor(@Inject(TextBoxService) private service: TextBoxService) {
  this.show = this.show.bind(this);
}

Decorators offer a cleaner syntax as well, for example, the @autobind from core-decorators.

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

Does an async function get automatically awaited if called in a constructor?

I am currently working on updating some code due to a library upgrade that requires it to be made async. The code in question has a base class that is inherited by other classes, and I need to call some functions in the constructor that are now asynchronou ...

Can Microsoft Edge Developer tool be used to incorporate external programs or code?

This image of msedge-devtools clearly demonstrates my point. I am interested in building a webpage parser using selenium and Microsoft Edge, beyond just JavaScript. I am seeking a way to utilize the Microsoft Edge developer tools (Inspect Element Mode) t ...

Stop the reloading of the parent page when the exit button is pressed on the popup screen

I have set up a modal popup that appears when a user clicks on a specific link. Inside the popup, I have included an exit button to close it. However, I am facing an issue where clicking on the exit button not only closes the popup but also reloads the par ...

Tips for confirming date is earlier than current date in Reactjs?

Looking for guidance on how to ensure a date selected by a user is always before the current date when using Material UI in my project. For instance, if it's January 6th, 2021 and the user selects either January 5th or 6th that would be acceptable. Ho ...

Is the existence of the file also verified by JavaScript's realpathSync() function?

I want to utilize node.js FileSystem realpathSync() to find the actual path of a file. Does realpathSync() also verify if the file exists? Would this code be sufficient: try { res = fs.realpathSync(path); } catch (err) { ...

Is npm create-react-app giving you trouble?

When attempting to create a React app using the command npm create-react-app appname, the tool would just return me to the same line to input more code. I also gave npx a try, but encountered some errors in the process. See this screenshot for reference: ...

Tips on fixing the "TypeError: Cannot read properties of undefined (reading 'lookup')" error message that occurs when running npm install

After successfully running npm install on a freshly cloned Angular project, I encountered an error with the node_modules when trying to launch the application using ng s. Could this issue be related to the version of Node.js being used? \node_modules& ...

Steps to resolve the error message 'Argument of type 'number' is not assignable to parameter of type 'string | RegExp':

Is there a way to prevent users from using special symbols or having blank spaces without any characters in my form? I encountered an error when trying to implement this in my FormGroup Validator, which displayed the message 'Argument of type 'nu ...

Tips for showing various tooltip text when iterating through a list?

I am currently working on a project where I am looping through a list and attempting to assign different tooltip text to various icons. However, I am struggling with the implementation. Here is a snippet of my code: <React.Fragment key={sv.key ...

Imposing the situation

In my current class, I have a private property and a public method for access: Person = function () { this.Name = "asd"; var _public = new Object(); _public.Name = function (value) { if (value == undefined) { //Get return ...

In TypeScript, the error "Property does not exist on type 'any[]'" indicates that a specific property is not recognized on

Working on my project using Textscript in Next Js has been mostly smooth sailing, but I keep encountering warnings in my script that say 'Property does not exist on type any[ ]'. The red line under the name, image, and price properties is a sourc ...

Navigate to another HTML division using data-toggle

I have 2 HTML documents index.html and services.html In services.html, I have the following code: <a class="nav-link" data-bs-toggle="tab" href="#ds-tab">Data Science</a> <a class="nav-link" data-bs- ...

trigger a label click when a button is clicked

I am in need of assistance with simulating a label click when a button is clicked. I attempted to make the label the same size as the button so that when the button is clicked, it would check my checkbox. I then tried using JavaScript to simulate the label ...

The React Testing Library encountered an error: TypeError - actImplementation function not found

Encountering a TypeError: actImplementation is not a function error while testing out this component import React from 'react'; import { StyledHeaderContainer, StyledTitle } from './styled'; export const Header = () => { return ( ...

Using React with TypeScript to ensure that at least one key of a type is not null, even if all keys are optional

Within my Typescript code, I have defined an event type that includes various time parameters: export type EventRecord = { name: string; eta: string | null; assumed_time: string | null; indicated_time: string | null; }; I also have a func ...

Send the contents of a `<ul>` element to the server using AJAX for form submission

Can someone assist me in submitting a serialized <ul> list through an AJAX post form request? I need help with this process. Below is my current code snippet. HTML: <form id="update_fruit_form" method="post" action="/update_fruits" accept-charse ...

Custom generator designed for projects with tailored ng/nrwl versions

Unfortunately, due to various reasons, we are unable to utilize angular version 12 at this time. As a result, we do not wish to use the current versions of ng and nrwl. I have been unable to find any documentation on how to generate a project with a speci ...

Can you explain the significance of the "@" symbol prefix found in npm package names?

While reading through the Angular Component Router documentation, I came across an npm command that caught my attention: npm install @angular/router --save I'm puzzled by the meaning of @angular/router. Is this entire string a package name? If so, ...

Adding optional properties to TypeScript interfaces

As discussed in this post, the optional ? operator is commonly used to indicate that a function parameter can be omitted. But what is the significance of the ? operator when it appears on interface parameters? For instance, consider the following TypeScrip ...

React Router is used to render routes that do not match the specified path

I am utilizing TypeScript in React Router. I have defined two routes: / and /pages/id. class MyComponent extends React.Component { render() { return <BrowserRouter> <div> <Route exact path='/' ch ...