lanetrotro
lanetrotro

Reputation: 357

stripe angular Error: Uncaught (in promise): TypeError: Cannot read property 'stripeService' of undefined

I'm currently trying to implement stripe to my angular4 nodejs application, but I kinda got stuck when i'm trying to send the card token to my server through my service handling the requests relateted to stripe. This is the code I got:

stripe.component.html :

<form role="form" id="payment-form">
    <div id="card-element"></div>
    <div id="card-errors" role="alert"></div>
    <button type="submit" (click)="addCard()">Submit Payment</button>
</form>

stripe.component.ts:

import {Component, OnInit} from "@angular/core";
import {WindowRef} from "../social/windowRef";
import {StripeService} from "./stripe.service";

@Component({
    selector: "app-stripe",
    templateUrl: './stripe.component.html',
    styleUrls: ['./stripe.component.css']
})
export class StripeComponent implements OnInit {
    elements: any;
    stripe: any;
    style: any;
    card: any;

    constructor(private stripeService: StripeService){}


    ngOnInit() {
        this.initCardElement();
    }

    initCardElement(){
        this.stripe = WindowRef.get().Stripe("my-key");
        this.elements = this.stripe.elements();
        this.style =
            {
                base: {
                    color: '#32325d',
                    lineHeight: '24px',
                    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
                    fontSmoothing: 'antialiased',
                    fontSize: '16px',
                    '::placeholder': {
                        color: '#aab7c4'
                    }
                },
                invalid: {
                    color: '#fa755a',
                    iconColor: '#fa755a'
                }
            };
        this.card = this.elements.create('card', {style: this.style});
        this.card.mount('#card-element');
    }


    addCard() {
        this.stripe.createToken(this.card)
            .then(function (result) {
                if (result.error) {
                    var errorElement = document.getElementById('card-errors');
                    errorElement.textContent = result.error.message;
                } else {
                    console.log(result.token);
                    this.stripeService.addCard(result.token)
                        .subscribe((response: Response) => {
                                console.log(response);
                            }
                        );
                }
            });
    }
}

I manage to get the stripe's card token but when i'm trying to call my stripeService I got this error:

Error: Uncaught (in promise): TypeError: Cannot read property 'stripeService' of undefined

i understand that this.stripeService is not defined here but I don't understand how I can solve this issue.

have a good day :)

Upvotes: 2

Views: 2555

Answers (2)

user8320472
user8320472

Reputation:

When you define a function, anonymous or named with the function keyword it creates a new scope, this keyword points to the scope of newly created function. What you want is to reference scope of the addCard function

There are a couple of ways to do this:

First and the best way is to use ES6 arrow functions which do not create a new scope eg:

this.stripe.createToken(this.card)
.then((result) => { 
    console.log(this.stripeService); // it will be defined here
})

Second option is to store reference to the scope of addCard:

let that = this;
this.stripe.createToken(this.card)
.then((result) => { 
    console.log(that.stripeService); // it will be defined here
})

Upvotes: 0

rsp
rsp

Reputation: 111434

Use arrow functions if you want to use the outer this. The functions declared with function create a new this which is undefined here.

Run this example to see what's going on:

class X {
  constructor(x) {
    this.x = x;
  }
  a() {
    (function () {
      console.log(this.x);
    })();
  }
  b() {
    (() => {
      console.log(this.x);
    })();
  }
}

let x = new X(10);
x.b();
x.a();

Here the function inside the b() method correctly uses the outer this but the a() method has a function that creates its own this which is undefined and results in the error:

TypeError: Cannot read property 'x' of undefined

In your example you can change this:

addCard() {
    this.stripe.createToken(this.card)
        .then(function (result) {
            if (result.error) {
                var errorElement = document.getElementById('card-errors');
                errorElement.textContent = result.error.message;
            } else {
                console.log(result.token);
                this.stripeService.addCard(result.token)
                    .subscribe((response: Response) => {
                            console.log(response);
                        }
                    );
            }
        });
}

to this:

addCard() {
    this.stripe.createToken(this.card)
        .then((result) => {
            if (result.error) {
                var errorElement = document.getElementById('card-errors');
                errorElement.textContent = result.error.message;
            } else {
                console.log(result.token);
                this.stripeService.addCard(result.token)
                    .subscribe((response: Response) => {
                            console.log(response);
                        }
                    );
            }
        });
}

(not tested)

Upvotes: 2

Related Questions