'Parsley + recaptcha v3 promise
I'm not able to get the following code to work:
$(function() {
function verifyRecaptcha() {
return new Promise((resolve, reject) => {
grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'submit'}).then(function(token) {
postJson('frontend/verify_recaptcha/'+token, null, function(d) {
if (d.pass) {
resolve('Verified');
} else {
reject('Not verified');
}
});
});
});
};
var parsleyForm = $('#enquiry-form').parsley().on('form:submit', function(formInstance) {
var validationResult = false;
verifyRecaptcha().then(function() {
console.log('VERIFIED');
validationResult = true
}).catch(function() {
console.log('NOT VERIFIED');
validationResult = false;
});
console.log('Resultat: '+validationResult);
return validationResult;
});
});
I already tried a lot with await/async, but it always submits the form.
I think I cannot be the only one who needs to implement Parsley with recaptcha v3? Any ideas? :)
Solution 1:[1]
I use this:
// Returns the current form that the recaptcha widget is appended on
const form = getRecaptchaForm();
// I use a different input from the standard 'g-recaptcha-response', but you can use the one appended by recaptcha
const input = form.elements.namedItem('g-recaptcha-response');
// Keep track of validation time
let lastToken, lastTokenDate;
// Use a polyfilled version of form.requestSubmit (https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit)
// See Safari bug: https://webkit.org/b/197958
const requestSubmit = function () {
let submitter = form.querySelector('input[type=\"submit\"],button[type=\"submit\"]');
if (!submitter) {
submitter = document.createElement('input');
submitter.type = 'submit';
submitter.hidden = true;
form.appendChild(submitter);
submitter.click();
form.removeChild(submitter);
}
else {
submitter.click();
}
};
// This submits the form as if the user clicked the submit button
const submitRecaptcha = function (token, error) {
lastToken = input.value = token;
lastTokenDate = Date.now();
if (error) {
console.warn('Recaptcha error', error);
}
requestSubmit();
};
// The submit handler must be bound on the form itself (not as a delegate from a parent)
form.addEventListener('submit', function handleRecaptcha(e) {
// Validation token is still valid
if ((input.value && (input.value === lastToken) && (lastTokenDate > (Date.now() - (2 * 60 * 1000)))) || (e.defaultPrevented === true) || (e.target !== form)) {
return;
}
try {
// Stop form submission and also prevent other handlers from triggering until the recaptcha promise is resolved
e.preventDefault();
e.stopPropagation();
// Validate the recaptcha
grecaptcha.ready(function () {
grecaptcha.execute('RECAPTCHA_SITE_KEY', { action: 'submit' })
.then(function (token) {
// Do something else with the token before submitting the form
postJson('frontend/verify_recaptcha/' + token, null, function(d) {
if (d.pass) {
// Now we trigger the other submit handlers (will also trigger our `handleRecaptcha` handler, but will return because the lastTokenDate is still valid)
submitRecaptcha(token);
}
else {
// Ensure the other submit handlers get triggered
submitRecaptcha('error', d);
}
});
})
.catch(function (e) {
// Ensure the other submit handlers get triggered
submitRecaptcha('error', e);
});
});
}
catch (e) {
// Ensure the other submit handlers get triggered
submitRecaptcha('error', e);
}
}, /* Must use capture phase to prevent other custom events from triggering ahead of this */ true);
The implementation is not parsley.js aware, you can theoretically use any validation library, but I tested it on a form that had parsley.js bound to it. The recaptcha checkbox decoration is handled by google, so there is no need to create a custom parsley.js async validator to handle it yourself.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |