Search code examples
angularangular-httpclientangular-http

Using the angular httpclient i receive this error TypeError: Cannot read properties of undefined (reading 'get')


I have to make an http request via Angular but the error written in the title appears whether I use 'post' or 'get' as if the http variable was undefined or uninitialized.

I checked the module and is imported correctly

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { HomePage } from './home.page';
import { ReactiveFormsModule } from '@angular/forms';
import { HomePageRoutingModule } from './home-routing.module';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    HomePageRoutingModule,
    HttpClientModule,
    ReactiveFormsModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

is also imported correctly

import { HttpClient } from '@angular/common/http';

and it seems that is also initialized correctly

constructor(private http: HttpClient, private navCtrl: NavController) { /* code */ }

these are the test functions I'm trying to use

this.http.get('https://jsonplaceholder.typicode.com/posts').subscribe((response: any) => {
          console.log(response);
      });
this.http.post('http://localhost:3000/api/charge/', token.id).subscribe((response: any) => {
          console.log(response);
        });

I'm sure the error is not server-side because sending an http request with a vscode http client works. For some strange reason, however, it's as if it doesn't find the get or post method inside the http variable. The complete error is as follows and it is the same if the request is a get or a post, it just changes who the undefined object is.

ERROR Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'get')
TypeError: Cannot read properties of undefined (reading 'get')
    at TokenCallback.<anonymous> (home.page.ts:127:19)
    at Generator.next (<anonymous>)
    at tslib.es6.js:76:1
    at new ZoneAwarePromise (zone.js:1429:21)
    at __awaiter (tslib.es6.js:72:1)
    at TokenCallback.token [as fn] (home.page.ts:123:40)
    at TokenCallback.trigger (checkout.js:3:12928)
    at TokenCallback.trigger (checkout.js:3:12207)
    at IframeView.onToken (checkout.js:3:9993)
    at IframeView.closed (checkout.js:3:17297)
    at resolvePromise (zone.js:1211:31)
    at new ZoneAwarePromise (zone.js:1432:17)
    at __awaiter (tslib.es6.js:72:1)
    at TokenCallback.token [as fn] (home.page.ts:123:40)
    at TokenCallback.trigger (checkout.js:3:12928)
    at TokenCallback.trigger (checkout.js:3:12207)
    at IframeView.onToken (checkout.js:3:9993)
    at IframeView.closed (checkout.js:3:17297)
    at Object.closed (checkout.js:3:13293)
    at RPC.processMessage (checkout.js:2:15310)

as requested here is the code i'm using. the loadstripe() function is called first and immediately after that the pay() function is called via two simple buttons in the html.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { PaymentSheetEventsEnum } from '@capacitor-community/stripe';
import { HTMLStencilElement } from '@stripe-elements/stripe-elements/dist/types/stencil-public-runtime';
import { Components, defineCustomElements } from '@stripe-elements/stripe-elements/loader';
import { Stripe } from '@capacitor-community/stripe';
import { NavController } from '@ionic/angular';
import { first } from 'rxjs';


@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  constructor(private http: HttpClient, private navCtrl: NavController) {
Stripe.initialize({
      publishableKey: 'private_key_im_using',
    });
  }
pay(amount: any) {

    var handler = (<any>window).StripeCheckout.configure({
      key: 'private_key_im_using',
      locale: 'auto',
      token: async function (token: any) {
        console.log(token);
        this.http.get('https://jsonplaceholder.typicode.com/posts').subscribe((response: any) => {
          console.log(response);
        });

//commented for testing
        /*this.http.post('http://localhost:3000/api/charge/', token.id).subscribe((response: any) => {
          console.log(response);
        });*/

        //await fetch('http://localhost:3000/api/charge/'+ token.id);

      }
    });

    handler.open({
    });

  }

  loadStripe() {

    if(!window.document.getElementById('stripe-script')) {
      var s = window.document.createElement("script");
      s.id = "stripe-script";
      s.type = "text/javascript";
      s.src = "https://checkout.stripe.com/checkout.js";
      s.onload = () => {
        this.handler = (<any>window).StripeCheckout.configure({
          key: 'private_key_im_using',
          locale: 'auto',
          token: function (token: any) {
            console.log(token)
            console.log('Payment Success');
          }
        });
      }

      window.document.body.appendChild(s);
    }
  }

}

the html code

<ion-item button="true" detail="true" (click)="loadStripe()"><ion-label>Test 1° click</ion-label></ion-item>
    <ion-item button="true" detail="true" (click)="pay(20)"><ion-label>Test 2° click</ion-label></ion-item>

Solution

  • The problem is, you are using this inside a nested function definition. That changes the scope of this. You can solve the problem with an arrow function. Arrow functions don't capture this.

    var handler = (<any>window).StripeCheckout.configure({
      key: 'private_key_im_using',
      locale: 'auto',
      token: async (token: any) => {
        console.log(token);
        this.http.get('https://jsonplaceholder.typicode.com/posts').subscribe((response: any) => {
          console.log(response);
        });
    
        //commented for testing
        /*this.http.post('http://localhost:3000/api/charge/', token.id).subscribe((response: any) => {
          console.log(response);
        });*/
    
        //await fetch('http://localhost:3000/api/charge/'+ token.id);
    
      }
    });