I want to render a recaptcha after a Vue.js component has mounted. It works on normal load and reload, but when I navigate away to a different url and click the browser back button it throws an error.
Here is my setup:
I am loading the
apiscript at the bottom of the page:<script src='https://www.google.com/recaptcha/api.js' async></script>on that page I render a globally registered component called
Contact.vuethat contains a local component calledRecaptcha.vue:<app-recaptcha @recaptchaResponse="updateRecaptchaResponse"></app-recaptcha>
The code for Recaptcha.vue looks like this:
<template>
<div id="app-recaptcha">
<div :id="placeholderId"></div>
</div>
</template>
<script>
export default {
data() {
return {
sitekey: 'key_here',
placeholderId: 'grecaptcha',
widgetId: null
}
},
mounted() {
this.$nextTick(function () {
this.render();
});
},
methods: {
render() {
this.widgetId = window.grecaptcha.render(this.placeholderId, {
sitekey: this.sitekey,
callback: (response) => {
this.$emit('recaptchaResponse', response);
}
});
},
reset() {
window.grecaptcha.reset(this.widgetId);
}
}
}
</script>
<style>...</style>
On normal page load/ reload this.render() is executed normally. However, when I navigate to another url and return via the back button I get: Error in nextTick: "TypeError: window.grecaptcha.render is not a function".
I tried to:
set a variable on the
onloadevent of theapiscript:<script src='...' onload="window.script = { recaptcha: 'ready' }" async></script>then add it as a property in
data()ofRecaptcha.vue:ready: window.script.recaptchanext, I added a watcher on the
readyproperty and within that watcher I tried to runthis.render()
No success, the error is still there. I think that even in the normal load/ reload situation I am simply "lucky" that the api script loads before the component gets mounted, and that placing this.render() inside the mounted() hook isn't helpful.
Do you know how can I signal Recaptcha.vue that the external script has finished loading, and only then render the recaptcha?