I'm developing a static website using SvelteKit to get my first approach to svelte. I got almost everything working as intended. Everything but the recaptcha protection on contact form.
I can obtain recaptcha token but I'm losing it the passing it to formData request. My relative code is:
<script lang="ts">
import * as yup from "yup";
import {createForm, ErrorMessage} from "svelte-forms-lib";
...
function getCaptcha(){
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) {
console.log(token) // here I get the token
return token;
});
});
}
const sendMail= (values)=>
{
const url = '/sendmail.php';
const formData = new FormData();
let token = getCaptcha();
console.log('token: '+token); // here token is null
formData.append("token", token);
fetch(url, {
method: 'post',
body: formData,
})
.then(function (response) {
console.debug(response.status)
})
.catch(function (e) {
sendError = true;
console.debug(e);
});
}
</script>
Form submission is working fine except, obviously, for recaptcha token.
Thanks for any idea on how to solve it.
token
is null because your getCaptcha
function isn't actually returning anything, since you're using callbacks to get the token.
function getCaptcha(){ // <- this function isn't returning anything
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) { // <- this function returns, but the value isn't going anywhere
console.log(token);
return token;
});
});
}
To fix this, you may want to look into using async
/await
syntax for promises. MDN has a great article if you're interested.
You would probably want to do something like this:
async function getCaptcha(){
await new Promise((resolve, reject) => {
// grecaptcha.ready needs a callback so we create a promise to await
grecaptcha.ready(resolve);
});
// grecaptcha.execute returns a promise so we can await it
const token = await grecaptcha.execute('recaptcha-key', { action: 'contactForm' });
console.log(token);
return token;
}
const sendMail = async (values) => {
const url = '/sendmail.php';
const formData = new FormData();
let token = await getCaptcha();
console.log('token: ' + token);
formData.append("token", token);
// you have a few options for converting
// the Promise.catch()
// you can use a try {} catch {} block
// or you can use .catch() on this sendMail function
try {
const response = fetch(url, {
method: 'post',
body: formData,
});
console.debug(response.status);
} catch (e) {
sendError = true;
console.debug(e);
}
}
Keep in mind that this will make the sendMail
function an async
function, which means you will have to await
calls to it, or use sendMail().then()
. I believe it's also possible to call async
functions directly in synchronous code and have them run, it's just not guaranteed that the stuff in the function will run before the code that comes after the call.