Stripe Elements with angular 2

Viewed 6462

I'm trying to integrate Stripe elements with angular 2 with an element card that accepts credit card information. Please note that, I'm not looking into using stripe checkout as there are several examples on this how to integrate stripe with angular 2.

declare var Stripe:any;

@Component({
  selector: 'app-account',
  templateUrl: './account.component.html',
  styleUrls: ['./account.component.scss']
})
export class AccountComponent implements OnInit {

  constructor(
    private _zone: NgZone
  ) { }

  private cardToken:any;

  ngOnInit() {

    if (typeof window !== 'undefined') {
      this.setUpCard();
    }
  }


  setUpCard() {
    var stripe = Stripe('TEST_API_KEY');
    var elements = stripe.elements();
    var style = {
      base: {
        fontSize: '16px',
        lineHeight: '24px'
      }
    };

    var card = elements.create('card', {style: style});

    card.mount('#card-element');
  }

  getCardData(number, month, year, cvc) {
      this.getCardToken(number, month, year, cvc);
  }

  getCardToken(number, month, year, cvc) {
    var dataObj = {"number": number, "exp_month": month, "exp_year": year, "cvc": cvc};

    Stripe.card.createToken(dataObj,
      (status, response) => { 

        this._zone.run(() => {
          if (status === 200) {
            this.cardToken = response;
            console.log("the card token: ", this.cardToken);
          }
          else {
            console.log("error in getting card data: ", response.error)
          }
        });
      }
    );
  }

HTML

<form role="form" id="payment-form">
  <div id="card-element">
    <!-- a Stripe Element will be inserted here. -->
  </div>
</form>

When my component loads I get this error:

The selector you specified (#card-element) applies to no DOM elements that are currently on the page. Make sure the element exists on the page before calling mount().

How can I access the dom element in angular 2 to work properly with Stripe?

Also, I'm using server side rendering on my angular app if this affects how angular works on the client somehow.

2 Answers

index.html

<script src="https://js.stripe.com/v3/"></script>

typings.d.ts

declare var Stripe: any;

StripeElementsComponent.ts

export class StripeElementsComponent implements AfterViewInit, OnDestroy { // import AfterViewInit, OnDestroy
    stripe: any;
    elements: any;
    card: any;
    apiKey = 'pk_test______________________'; //replace with your api key
    cardHandler = this.onChange.bind(this);
    error: string;
    @ViewChild('cardInfo') cardInfo: ElementRef; //import viewChild ElementRef

    constructor(private cdr: ChangeDetectorRef) {} //import ChangeDetectorRef

    ngAfterViewInit() {
        this.stripe = Stripe(this.apiKey);
        this.elements = this.stripe.elements();
        const style = { // input card style optional
            base: {
                fontSize: '16px',
                color: '#32325d',
            },
        };
        this.card = this.elements.create('card', {
            style
        });
        this.card.mount(this.cardInfo.nativeElement);
        this.card.addEventListener('change', this.cardHandler);
    }

    ngOnDestroy() {
        this.card.removeEventListener('change', this.cardHandler);
        this.card.destroy();
    }

    onChange({
        error
    }) {
        if (error) {
            this.error = error.message;
        } else {
            this.error = null;
        }
        this.cdr.detectChanges();
    }

    async onSubmitStripe(form: NgForm) { // import NgForm
        const {
            token,
            error
        } = await this.stripe.createToken(this.card);

        if (error) {
            console.log('Something is wrong:', error);
        } else {
            console.log('Success!', token); //response 
        }
    }
}

StripeElementsComponent.html

<form #checkout="ngForm" (ngSubmit)="onSubmitStripe(checkout)">
    <div class="form-row">
        <label for="card-element">Credit or debit card</label>
        <div id="card-element" #cardInfo></div>
        <div id="card-errors" role="alert" *ngIf="error">{{ error }</div>
    </div>
<button>Submit Payment</button>

StripeElementsComponent.css

.StripeElement {
  transition: box-shadow 150ms ease;
  border: solid 3px #e3e3e3;
  border-radius: 0.5em;
  padding: 1.143em 1em;
}

.StripeElement--focus {
  border-color: #85b7d9;
}

.StripeElement--invalid {
  border-color: #fa755a;
}

.StripeElement--webkit-autofill {
  background-color: #fefde5 !important;
}
Related