Mihai
Mihai

Reputation: 2937

Defer execution until external script has loaded in Vue.js

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:

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:

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?

Upvotes: 9

Views: 7582

Answers (1)

LShapz
LShapz

Reputation: 1756

okay, here's a theory: add data properties

captchaReady: false, 
checkingInterval: null,

created

let localThis = this 
this.checkingInterval = setInterval(function(){
  if (window.grecaptcha) {
    localThis.captchaReady = true
  }
}, 500) //or whatever interval you want to check 

Then

watch: {
  captchaReady: function(data) {
    if (data) { 
       clearInterval(this.checkingInterval) 
       this.render()
    }
  }
}

Upvotes: 11

Related Questions