I'm trying to validate my form before the stripe payment modal appears, but the modal appears before the form can be validated. I'm using jquery validation plugin for my validation. I've tried adding the Stripe integration code in the submitHandler function, but still no luck. Below is what I currently have for my code:
<!-- google & apple pay btn -->
<div id="payment-request-button"
class="btn__link btn__link--fullwidth-mob btn__link--paypal-flex btn__link--marginLeft-0">
<%--A Stripe Element will be inserted here--%>
</div>
<!-- google & apple validation btn -->
<input id="paymentRequestButtonValidation"
class="btn__link btn__link--fullwidth-mob btn__link--secondary btn__submit"
type="submit" value="G Pay Validation">
var btnSubmitId = '';
//-- get the id of the btn submit
$('.btn__submit').click(function (event) {
btnSubmitId = event.target.id;
});
/* Stripe Integration */
let searchParams = new URLSearchParams(window.location.search);
var urlAmount = searchParams.get('Amount');
var urlAmountNum = parseFloat(urlAmount);
var donationAmount = urlAmountNum * 100;
var clientSecret = "<%= clientSecret %>";
var stripe = Stripe(stripeCredentials);
var paymentRequest = stripe.paymentRequest({
country: 'GB',
currency: 'gbp',
total: {
label: 'Test payment',
amount: donationAmount
},
requestPayerName: true,
requestPayerEmail: true,
});
var elements = stripe.elements();
var prButton = elements.create('paymentRequestButton', {
paymentRequest: paymentRequest,
});
// Check the availability of the Payment Request API first.
paymentRequest.canMakePayment().then(function (result) {
if (result) {
// if available mount/create the button
prButton.mount('#payment-request-button');
} else {
// if NOT available hide the button and console log it
document.getElementById('payment-request-button').style.display = 'none';
console.log('ERROR - btn not available & can\'t be mounted');
}
});
paymentRequest.on('paymentmethod', function (ev) {
// Confirm the PaymentIntent without handling potential next actions (yet).
stripe.confirmCardPayment(
clientSecret, { payment_method: ev.paymentMethod.id},
{ handleActions: false }
).then(function (confirmResult) {
if (confirmResult.error) {
// Report to the browser that the payment failed, prompting it to
// re-show the payment interface, or show an error message and close
// the payment interface.
ev.complete('fail');
} else {
// Report to the browser that the confirmation was successful, prompting
// it to close the browser payment method collection interface.
ev.complete('success');
// Check if the PaymentIntent requires any actions and if so let Stripe.js
// handle the flow. If using an API version older than "2019-02-11"
// instead check for: `paymentIntent.status === "requires_source_action"`.
if (confirmResult.paymentIntent.status === "requires_action") {
// Let Stripe.js handle the rest of the payment flow.
stripe.confirmCardPayment(clientSecret).then(function (result) {
if (result.error) {
// The payment failed -- ask your customer for a new payment method.
} else {
// The payment has succeeded.
}
});
} else {
// The payment has succeeded.
}
}
});
prButton.on('click', function (ev) {
// get the current amount from the #donationValue inout field
paymentRequest.update({
total: {
label: 'Test payment',
amount: $("#donationValue").val() * 100,
},
});
})
});
// -- single form validation
$('#singleForm').validate({
rules: {
donationValue: {
required: true,
number: true,
twoDecimal: true
},
donationtype: {
required: true
},
firstname: {
required: true
},
lastname: {
required: true
},
email: {
required: true
},
addressSearch: {
required: true
},
address1: {
required: true
},
postcode: {
required: function (e) {
return $(e).closest('form').find('#country').val() == 'United Kingdom';
}
},
town: {
required: true
},
country: {
required: true
},
mobile: {
required: '#receiveSMS:checked'
}
},
messages: {
donationValue: {
required: 'Please enter your donation amount.',
number: 'Please enter a valid donation amount.'
},
donationtype: 'Please select one of the options for Gift Aid.',
firstname: 'Please enter a valid first name.',
lastname: 'Please enter a valid last name.',
email: 'Please enter a valid email address.',
addressSearch: 'Please enter a valid postcode, street name or address.',
address1: 'Please enter a valid address.',
postcode: 'Please enter a valid postcode.',
town: 'Please enter a valid town/city.',
country: 'Please select a valid country.',
mobile: 'Please enter your mobile phone number above'
},
highlight: function (element) {
$(element).parent().find('span').addClass('error__text--icon');
$(element).parent().find('input').addClass('form__input--error');
$(element).parent().find('select').addClass('form__input--error');
if (element.id == 'dtOwnDonation') {
$(element).parent().find('span').removeClass('error__text--icon');
}
},
unhighlight: function (element) {
$(element).parent().find('span').removeClass('error__text--icon');
$(element).parent().find('input').removeClass('form__input--error');
$(element).parent().find('select').removeClass('form__input--error');
},
submitHandler: function () {
if (btnSubmitId == 'singleBtnValidation') {
$('#singleBtn').click();
console.log('debit/credit card form - validation successful');
} else if (btnSubmitId == 'paymentRequestButtonValidation') {
console.log('paymentRequestButtonValidation - validation successful');
}
}
});
Thanks in advance!
So you're using PaymentRequest Button, which by default does not give your webpage an event when the browser modal (e.g. Apple Pay or Google Pay) is shown (when PaymentRequest Button is pressed by the customer).
What you can instead do is manually mount your own button (styled as an Apple Pay or Google Pay button depending on the browser) and then manually show the PaymentRequest Button sheet using paymentRequest.show()
: https://stripe.com/docs/js/payment_request/show
That way, you can do any form validation on the button press. The Stripe docs mention this approach for using your own button here: https://stripe.com/docs/stripe-js/elements/payment-request-button?html-or-react=html#html-js-own-button