app/webpacker/controllers/stripe_controller.js
import { Controller } from "stimulus";
export default class extends Controller {
static targets = [
"cardElement",
"cardErrors",
"expMonth",
"expYear",
"brand",
"last4",
"pmId",
];
static styles = {
base: {
fontFamily: "Roboto, Arial, sans-serif",
fontSize: "16px",
color: "#5c5c5c",
"::placeholder": {
color: "#6c6c6c",
},
},
};
initialize() {
this.parentForm = this.pmIdTarget.form;
this.catchFormSubmit = true;
// Initialize Stripe JS
this.stripe = Stripe(this.data.get("key"));
this.stripeElement = this.stripe
.elements({ locale: I18n.base_locale })
.create("card", {
style: this.constructor.styles,
hidePostalCode: true,
});
// Mount Stripe Elements JS to the form field
this.stripeElement.mount(this.cardElementTarget);
}
connect() {
this.parentForm.addEventListener("submit", this.stripeSubmit);
this.stripeElement.addEventListener("change", this.updateErrors);
}
disconnect() {
this.parentForm.removeEventListener("submit", this.stripeSubmit);
this.stripeElement.removeEventListener("change", this.updateErrors);
}
// Before the form is submitted we send the card details directly to Stripe (via StripeJS),
// and receive a token which represents the card object, and add that token into the form.
stripeSubmit = (event) => {
if (!this.stripeSelected() || !this.catchFormSubmit) {
return;
}
event.preventDefault();
event.stopPropagation();
this.stripe
.createPaymentMethod({ type: "card", card: this.stripeElement })
.then((response) => {
if (response.error) {
this.updateErrors(response);
} else {
this.pmIdTarget.setAttribute("value", response.paymentMethod.id);
this.expMonthTarget.setAttribute(
"value",
response.paymentMethod.card.exp_month
);
this.expYearTarget.setAttribute(
"value",
response.paymentMethod.card.exp_year
);
this.brandTarget.setAttribute(
"value",
response.paymentMethod.card.brand
);
this.last4Target.setAttribute(
"value",
response.paymentMethod.card.last4
);
this.catchFormSubmit = false;
event.submitter.click();
}
});
};
// Update validation messages from Stripe shown in the form
updateErrors = (data) => {
if (data.error) {
this.cardErrorsTarget.textContent = data.error.message;
} else {
this.cardErrorsTarget.textContent = "";
}
};
// Boolean; true if Stripe is shown / currently selected
stripeSelected() {
return !!this.cardElementTarget.offsetParent;
}
}