Search code examples
javascriptvue.jsrecaptchavue-router

ReCaptcha v2 won't load in vue-router navigation


I am using Google ReCaptcha v2 which I am integrating it for the registration process. So, when the user goes /register, it loads the RegisterComponent.

However, the reCaptcha won't load when say I'm in Homepage and navigate to the /register via a button. Why is it happening?

I am loading the script in layouts.master.php:

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

And loading the reCaptcha in Register Component like so:

<div class="field">
    <div class="control" id="recaptcha-reg">
        <div class="g-recaptcha" data-sitekey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"></div>
        <span v-if="regErrors.captcha" v-for="error in errors">{{ error }}</span>
    </div>
</div>

This reCaptcha is then validated using PHP. So, there's no JS Logic! Please help!


Solution

  • If anyone is having the same problem, here's how to solve it:

    • Assign the id to your reCaptcha widget.
    • And then when the component is created, run setTimeout to render the widget.

    Example:

    <div id="recaptcha-main" class="g-recaptcha" data-sitekey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"></div>
    

    And then in your component where you want to load the captcha:

    created() {
        setTimeout(() => {
            grecaptcha.render('recaptcha-main'); // 'recaptcha-main' is the id that was assigned to the widget
        }, 2000);
    }
    

    That's it!

    UPDATED - THE BEST APPROACH

    Instead of using setTimeout, use nextTick() instead which basically runs only after the view incl. the children are finished loading.

    You assign the id and then run this inside of your created hook:

    this.$nextTick(function () {
        grecaptcha.render('recaptcha-main');
    })
    

    The drawback of setTimeout is it runs only after the specified time. Say 1 second for example. So, if your component takes >1 second to load fully, then the setTimeout may not work here as it will be executed immediately after 1 second.

    I hope this works for you :)