Integrating Stripe Payment Gateway In Angular | Stripe Payment Checkout Example

Abhinav Akhil
7 min readApr 18, 2023

--

Integrating a payment gateway in an Angular application is a common requirement for e-commerce websites or any app that requires online payments. Stripe is a popular payment gateway that provides a secure and easy way to process online payments. In this tutorial, we will be discussing how to integrate the Stripe payment gateway in Angular using the ngx-stripe library.

ngx-stripe is a third-party Angular library that provides a wrapper around Stripe.js, which is Stripe’s JavaScript library for interacting with the Stripe API. ngx-stripe simplifies the process of integrating Stripe into an Angular application by providing pre-built Angular components and services that can be used to create and manage payments using Stripe.

The library provides a range of features, including integration with Stripe Elements for securely collecting credit card information, support for various Stripe APIs such as the Payment Intent API and the Payment Method API, and support for various payment scenarios such as single payments, recurring payments, and subscription payments.

First of all, we need to create a Stripe account by going to https://stripe.com/ and signing up for a new account. Once you have created your account, you can access your API keys from the Stripe Dashboard.

The next step is to install the ngx-stripe library in your Angular project. You can install it using npm by running the following command:

npm install ngx-stripe --save

After installing ngx-stripe, you need to configure it with your Stripe API keys. You can store that in a variable & to do this, open the environment.ts file and add the following code:

export const environment = {
production: false,
stripe: {
publicKey: 'YOUR_PUBLIC_KEY',
}
};

Replace YOUR_PUBLIC_KEY with your actual Stripe public API key.

Now, you need to import the ngx-stripe module into your Angular module. Open the app.module.ts file and add the following code:

import { NgxStripeModule } from 'ngx-stripe';
import { environment } from '../environments/environment';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
NgxStripeModule.forRoot(environment.stripe.publicKey)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

This imports the NgxStripeModule and configures it with your Stripe public API key.

Next, you need to create a payment form in your Angular app where users can enter their payment details, such as credit card number, expiry date, and CVC. You can create a payment form using HTML and Angular forms.

Here is an example of custom payment form:

<form [formGroup]="paymentForm" (ngSubmit)="submit()">
<input type="text" formControlName="name" placeholder="Name">
<input type="text" formControlName="email" placeholder="Email">
<input type="text" formControlName="amount" placeholder="Amount">
<div id="card-element"></div>
<button type="submit" [disabled]="!paymentForm.valid">Submit Payment</button>
</form>

or we can use the Stripe Elements components which provide a flexible way to securely collect payment information in your Angular app.

You can mount individual Element components inside of your Elements tree. Note that you can only mount one of each type of Element.

Here is an example of a payment form using ngx-stripe elements:

<form class="checkout-form" [formGroup]="paymentForm">

<input type="text" formControlName="name" placeholder="Name"/>
<input type="text" formControlName="email" placeholder="Email">
<input type="number" formControlName="amount" placeholder="Amount"/>

<div class="stripe-card" ngxStripeCardGroup [elementsOptions]="elementsOptions">
<h4>Enter payment details</h4>

<div class="stripe-element">
<ngx-stripe-card-number
[options]="cardOptions"
[elementsOptions]="elementsOptions"
></ngx-stripe-card-number>
</div>

<div fxLayout="row" fxLayoutGap="10px">
<div class="w-full stripe-element">
<ngx-stripe-card-expiry
[options]="cardOptions"
></ngx-stripe-card-expiry>
</div>
<div class="w-full stripe-element">
<ngx-stripe-card-cvc
[options]="cardOptions"
></ngx-stripe-card-cvc>
</div>
</div>
</div>

<button type="submit" (click)="pay(payment_method)">Submit Payment</button>
</form>

Here we have used the card number, expiry, and CVC as separated elements so you need to put them inside the card group directive.

This is necessary to ensure the three elements shared the same stripe elements objects, otherwise it won’t work. As you can see in the example element options is not available for any of the three child components, but only for the group directive.

Here is the list of all the available card elements Components

Now in the component, we will add the configuration of the stripe card elements.

import { Component, OnInit, ViewChild } from '@angular/core';
import { StripeCardNumberComponent } from 'ngx-stripe';
import {
StripeCardElementOptions,
StripeElementsOptions,
} from '@stripe/stripe-js';

@Component({
selector: 'app-payment-form',
templateUrl: './payment-form.component.html',
styleUrls: ['./payment-form.component.css']
})
export class PaymentFormComponent implements OnInit {

@ViewChild(StripeCardNumberComponent) card: StripeCardNumberComponent;

public cardOptions: StripeCardElementOptions = {
style: {
base: {
fontWeight: 400,
fontFamily: 'Circular',
fontSize: '14px',
iconColor: '#666EE8',
color: '#002333',
'::placeholder': {
color: '#919191',
},
},
},
};

public elementsOptions: StripeElementsOptions = {
locale: 'en',
};

constructor() {}

ngOnInit() {}

}

The card options for the Stripe card element are used to set the appearance of the card element. You also need to define the Stripe elements options. This can be used to set the locale for the payment form.

@ViewChild(StripeCardNumberComponent)is used to reference the StripeCardNumberComponent, which is part of the ngx-stripe library. This allows you to access the StripeCardNumberComponent's properties and methods, such as the element property which references the Stripe Element object associated with the card input field.

  paymentForm: FormGroup = this.fb.group({
name: ['John', [Validators.required]],
email: ['john@gmail.com', [Validators.required]],
amount: [100, [Validators.required, Validators.pattern(/d+/)]],
});

constructor(
private http: HttpClient,
private fb: FormBuilder,
private stripeService: StripeService
) {}

ngOnInit(): void {

}

pay(): void {
if (this.paymentForm.valid) {
this.createPaymentIntent(this.paymentForm.get('amount').value)
.pipe(
switchMap((pi) =>
this.stripeService.confirmCardPayment(pi.client_secret, {
payment_method: {
card: this.card.element,
billing_details: {
name: this.paymentForm.get('name').value,
},
},
})
)
)
.subscribe((result) => {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
}
}
});
} else {
console.log(this.paymentForm);
}
}

createPaymentIntent(amount: number): Observable<PaymentIntent> {
return this.http.post<PaymentIntent>(
`${env.apiUrl}/create-payment-intent`,
{ amount }
);
}

Let’s break down the code to understand how it works.

The first part of the code defines a FormGroup using FormBuilder. The FormGroup represents the payment form that users will fill out to make a payment. The FormGroup contains three fields: name, email, and amount.

The constructor of the component injects several dependencies: HttpClient, FormBuilder, and StripeService. HttpClient is used to make HTTP requests to the server, FormBuilder is used to create the FormGroup, and StripeService is a library provided by Stripe.

Finally, we come to the pay function. This function is called when the user clicks the “pay” button on the payment form. The function first checks if the payment form is valid. If it is not valid, an error message is logged to the console. If it is valid, the function calls the createPaymentIntent function with the amount from the payment form.

The createPaymentIntent function is responsible for creating a payment intent with Stripe. A payment intent represents a single payment attempt. This function takes the amount from the payment form and sends an HTTP request to the server to create a payment intent with Stripe. The server responds with a client_secret, which is used later to confirm the payment

The function then calls the StripeService.confirmCardPayment function, passing in the client_secret and the payment details, including the card and billing details. The StripeService.confirmCardPayment function sends a request to Stripe to confirm the payment using the provided details.

If the payment is successful, the result.paymentIntent.status will be ‘succeeded’. If there is an error, the error message will be logged to the console.

Here is the full code of the component file:

import { Component, OnInit, ViewChild } from '@angular/core';
import { switchMap } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
import { StripeCardNumberComponent, StripeService } from 'ngx-stripe';
import {
StripeCardElementOptions,
StripeElementsOptions,
PaymentIntent,
} from '@stripe/stripe-js';
import { environment as env } from '../../environments/environment';

@Component({
selector: 'app-payment-form',
templateUrl: './payment-form.component.html',
styleUrls: ['./payment-form.component.css']
})
export class PaymentFormComponent implements OnInit {

@ViewChild(StripeCardNumberComponent) card: StripeCardNumberComponent;

public cardOptions: StripeCardElementOptions = {
style: {
base: {
fontWeight: 400,
fontFamily: 'Circular',
fontSize: '14px',
iconColor: '#666EE8',
color: '#002333',
'::placeholder': {
color: '#919191',
},
},
},
};

public elementsOptions: StripeElementsOptions = {
locale: 'en',
};

paymentForm: FormGroup = this.fb.group({
name: ['John', [Validators.required]],
email: ['john@gmail.com', [Validators.required]],
amount: [100, [Validators.required, Validators.pattern(/d+/)]],
});

constructor(private http: HttpClient,
private fb: FormBuilder,
private stripeService: StripeService) {}

ngOnInit() {}

pay(): void {
if (this.paymentForm.valid) {
this.createPaymentIntent(this.paymentForm.get('amount').value)
.pipe(
switchMap((pi:any) =>
this.stripeService.confirmCardPayment(pi.client_secret, {
payment_method: {
card: this.card.element,
billing_details: {
name: this.paymentForm.get('name').value,
},
},
})
)
)
.subscribe((result) => {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
}
}
});
} else {
console.log(this.paymentForm);
}
}

createPaymentIntent(amount: number): Observable<PaymentIntent> {
return this.http.post<PaymentIntent>(
`${env.apiUrl}/create-payment-intent`,
{ amount }
);
}

}

For creating payment intent please integrate this ( /create-payment-intent ) in a backend app.

Run the application using ng serve --o and you should see a form like this.

Now let's test: You can try adding the following test card numbers provided by Stripe for development purposes.

4242424242424242: Succeeds and immediately processes the payment.
4000000000009995: Always fails with a decline code of insufficient_funds.
CVV: Any 3 digit number

Date: Any future date.

In conclusion, the code we have discussed shows how to integrate Stripe payment in an Angular application using the ngx-stripe. By using the FormGroup and FormBuilder to build the form, and the StripeService and HttpClient to integrate the payment, we can create a seamless payment experience for our users. Remember to test your application thoroughly to ensure that it is working as expected. I hope this article has been helpful in understanding how to integrate Stripe payment in an Angular application.

Please feel free to ask me any questions or give any suggestions.

Thanks for reading and happy coding!

--

--

Abhinav Akhil
Abhinav Akhil

Written by Abhinav Akhil

I create software, that tell stories.

Responses (3)