Invoking method while returning a promise in Angular/Typescript

My Angular component is designed to read XML files and parse the data to display it on an HTML table. I'm trying to enhance the functionality of the displayed data by making modifications as specific points in the XML file are reached. However, whenever I attempt to call a method that should return the modified data, I encounter the following error message:

"core.js:15724 ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'CurrencyConvChange' of undefined TypeError: Cannot read property 'CurrencyConvChange' of undefined".

Below is the TypeScript code for my main component:

import { Component, OnInit } from '@angular/core';
import * as xml2js from 'xml2js';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { DataStoreService } from '../../data-store.service';

@Component
({
  selector: 'app-tableofshares',
  templateUrl: './tableofshares.component.html',
  styleUrls: ['./tableofshares.component.css']
})

export class TableofsharesComponent
{
  public xmlItems: any;
  new_curr_value;
  test_1 = 1;
  test_2 = 1;

  constructor(private http: HttpClient, private store: DataStoreService)
  // tslint:disable-next-line: one-line
  {
    this.loadXML(); // Runs below function when the project is started.
  }

  async CurrencyConvChange(test_1, test_2)
  {
    console.dir("recieved test 1: " + test_1);
    console.dir("recieved test 2: " + test_2);
    return 0;
  }

  // Loads the data
  loadXML()
  {
    this.http.get('assets/Shares_Data.xml',
    {
      headers: new HttpHeaders()
      .set('Content-Type', 'text/xml')
      .append('Access-Control-Allow-Methods', 'GET')
      .append('Access-Control-Allow-Origin', '*')
      // tslint:disable-next-line: max-line-length
      .append('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Access-Control-Allow-Origin, Access-Control-Request-Method'),
      responseType: 'text'
    }).subscribe((data) => {
      this.parseXML(data).then((data) =>
      {
        this.xmlItems = data; // Assigns xmlItems data from request
      });
    });
  }

  // Manipulates the data
  async parseXML(data)
  {
    return new Promise(resolve =>
    {
      let k: string | number,
      arr = [],
      test_var,
      parser = new xml2js.Parser({trim: true, explicitArray: true});

      parser.parseString(data, function(err, result)
      {
        const obj = result.ShareList;
        // tslint:disable-next-line: forin
        for (k in obj.share)
        {
          const item = obj.share[k];
          const test_1 = item.sharePrice[0].currency[0];
          console.dir("test 1: " + test_1);

          const test_2 = item.sharePrice[0].value[0];
          console.dir("Test 2: " + test_2);

          this.CurrencyConvChange(test_1, test_2);

          arr.push
          ({
            title: item.title[0], companySymbol: item.companySymbol[0],
            numOfShares: item.numOfShares[0], lastShareUpdate: item.lastShareUpdate[0],
            currency: item.sharePrice[0].currency, value: item.sharePrice[0].value
          });
        }
        resolve(arr);
      });
    });
  }
}

The error arises when I try to call my desired method with the line "this.CurrencyConvChange(test_1, test_2)". I'm puzzled by this error since I've defined the method CurrencyConvChange before any other methods. As a newcomer to TypeScript, I'm curious if this issue stems from a rule I may have overlooked?

Answer №1

This issue is not related to typescript or promises, but rather to the this reference.

The problem arises when trying to access this inside a callback function.

 parser.parseString(data, function(err, result)

Attempting to access this within that function leads to issues.

 this.CurrencyConvChange

In order to correctly reference the desired this, use an arrow function for defining the callback like so:

 parser.parseString(data, (err, result) => ....

Alternatively, you can use a workaround to solve this problem:

let that = this; // declare outside of the function
// then, within your function
that.CurrencyConvChange 

Answer №2

One simple solution that I frequently use is to add the following line in your class:

static _self: any;

Then, in your constructor, do this assignment:

YourComponent._self = this;

Now you can easily access your methods like this:

YourComponent._self.customMethod(param1, param2). 

If there are better alternatives, please share them so I can improve my code.

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

Navigating the Angular2 @angular/router 3.0.0-alpha.3 - Ways to access the route name or path upon route transitions

In my app.component, I am currently looking for a way to access the current route name or path when the route changes. My goal is to use the route name as a page class for a wrapper div. I had previously been subscribing to the router changes property as ...

Using Angular 6 HttpClient to retrieve an object of a specific class

Previously, we were able to validate objects returned from http api calls using the instanceof keyword in Angular. However, with the introduction of the new HttpClient Module, this method no longer works. I have tried various simple methods, but the type c ...

Utilizing a Single Class with TypeScript in Angular and Node.js Servers: Best Practices

I've named the file containing the following code as models.ts import {BusStage} from "./busStage"; export class BusRoute { name: string; origin_direction_1: string; origin_direction_2: string; stops: number; id: string; meta ...

Transferring image Buffer over API for uploading to IPFS network

My attempt to upload an image to IPFS involves the following steps: I start by uploading the image from my web UI, converting it to a buffer in my Angular component. The next step is to send it via a put/post request (using HttpClient) to my NodeJS Expres ...

TypeScript error message: "The 'new' keyword cannot be used with an expression that does not have a call or construct signature."

Encountered a problem with intersection types in TypeScript... There are three type aliases: Prototype<T> - representing an object or class with a prototype property. DefaultCtor<T> - representing an object or class with a default construct ...

Strategies for Refreshing a Component After Modifying Data in the Store

Having trouble updating my table component when the data in my store changes. I have a simple table using v-for as shown below: <tr v-for="d in getDatas" v-bind:key="d.id"> and buttons to navigate between pages: <button class= ...

The error message indicates a change in the binding value within the template, resulting in an

This is the structure of my component A : <nb-tab tabTitle="Photos" [badgeText]="centerPictures?.pictures?.length" badgePosition="top right" badgeStatus="info"> <app-center-pictures #centerPictures [center]="center"> ...

angular directive to receive an object

When I have a table and click on a row, the information is supposed to be displayed in a different component using the @input decorator. However, instead of displaying the correct result in my other component, I am getting [object Object]. table.html < ...

Performing operations in between each subscription using RxJS

I have successfully created an angular pipe that converts text into spoken words. Currently, I am working on implementing a feature where the user can view the sentence being spoken while the audio is playing, instead of after it has finished (which is ho ...

Error in Express Session: Property 'signin' is not found in type 'Session & Partial<SessionData>'. Code: 2339

I received the following Error Code: Property 'signin' does not exist on type 'Session & Partial<SessionData>'. (2339) About My Application src/index.ts import "reflect-metadata"; import express = require("expr ...

The Vue3 module does not have any exported members available

I am seeking assistance with a Vue component. I have encountered an error message that states: Failed to compile. src/components/Btn/Btn.vue:11:14 TS2305: Module '"../../typings/button-type"' has no exported member 'ButtonType&apo ...

Error TS2564: Variable 'signupForm' must be assigned a value either in the constructor or during declaration

Utilizing ViewChild to handle angular form submission. See the code snippet below: app.component.ts import { Component, ViewChild } from '@angular/core'; import { NgForm } from '@angular/forms'; @Component({ selector: 'app-root ...

What is the best way to retrieve the value from a Material UI textfield after hitting the enter key

Having trouble retrieving input values with the provided code. Attempted using onKeyUp, onKeyDown, and onKeyPress, but none of them returned the value as desired. Typically, I would use the onChange property to get the value, but it triggers for every ne ...

Encountering an "Undefined" error while assigning an Observable within a map function in TypeScript

I'm currently diving into the world of observables and facing some challenges along the way. Within my save() function, I call initialize() to retrieve certain Id's. In the initialize function, I am setting an Observable using a map method (payl ...

Ensure that the Angular Material Autocomplete (mat-autocomplete) always appears below the input field

Is there any way to make the Angular Material Autocomplete(mat-autocomplete) always open at the bottom of the input field? Do I need to use a position configuration or can this be achieved with CSS techniques? ...

Having trouble sending data with a POST request using Angular 4's HttpClient?

Angular 4.4.4 This is an introduction to my app component constructor( private http: HttpClient, ) this.http.post('/api.php', {name, age}).subscribe(response => { console.log(response); }); api.php -> exit(json_encode($_P ...

What is the most efficient method for validating an exception in Protractor?

In recent code reviews within our team, a discussion arose about writing tests that assert on expected exceptions. While this is correct, the method used involved a try/catch block, which some believe may not be the most performant approach. This raises th ...

Unable to remove loading.tsx file

Currently tackling a project using Next.js, I decided to include loading.tsx within the app directory. However, upon attempting to delete it, an error crops up: Caused by: The system cannot find the file specified. (os error 2) The import trace for the r ...

The usage of Arrow Functions and Inheritance within TypeScript

Currently, I am immersing myself in TypeScript with the guidance of Barasat Ali Syed's Deep Dive. While exploring Arrow Functions and inheritance, I stumbled upon the following code snippet. Could you please assist me in comprehending the significanc ...

Issue encountered in Angular 4 due to XSS script in URL causing "Cannot match any routes" error

I've been working on a project in Angular 4 and encountered an issue while setting up routes for a feature module. The error message I'm receiving is Error: Cannot match any routes. Below is the code snippet of the routes I've defined: con ...