Wait to execute until the external script in Vue.js has finished loading

How can I trigger the rendering of a recaptcha after a Vue.js component has mounted? It functions correctly on initial load and reload, but throws an error when navigating away to a different url and using the browser back button.

Here is how it's set up:

  • The api script is loaded at the bottom of the page like this:

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

  • On that page, a globally registered component named Contact.vue is rendered which contains a local component called Recaptcha.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>

During normal page load or reload, this.render() runs without issues. However, upon returning via the browser back button from another url, an error is triggered:

Error in nextTick: "TypeError: window.grecaptcha.render is not a function"
.

I attempted to:

  • set a variable on the onload event of the api script:

    <script src='...' onload="window.script = { recaptcha: 'ready' }" async></script>

  • then add it as a property in data() of Recaptcha.vue:

    ready: window.script.recaptcha

  • next, I added a watcher on the ready property and within that watcher I tried to run this.render()

Unfortunately, I was unsuccessful in resolving the error. It seems that even during normal load/reload situations, the api script may be loading after the component mounts, rendering this.render() in the mounted() hook ineffective.

Do you have any suggestions on how I can notify Recaptcha.vue when the external script has finished loading, ensuring the recaptcha is rendered only then?

Answer №1

Let's explore a theory: integrating data properties

isCaptchaReady: false, 
intervalId: null,

Initiated

let self = this;
this.intervalId = setInterval(function(){
  if (window.grecaptcha) {
    self.isCaptchaReady = true;
  }
}, 500) //adjust the interval as needed

Next

watch: {
  isCaptchaReady: function(data) {
    if (data) { 
       clearInterval(this.intervalId);
       this.render();
    }
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

unique array that shuffles every time it is reloaded, utilizing only javascript

I have created a string array that holds 6 different classes. Whenever I click a button, a new class is generated randomly. However, the issue arises when I click the button again and get the same class instead of a new random one. Even after reloading the ...

`In AngularJS, the default selection option is not functioning as expected`

I'm struggling with a particular issue in my code. <select ng-model="selected_student" class="form-control"> <option ng-repeat="obj in students" value="{{obj.id}}">{{obj.name}}</option> </select> When I try to set the sel ...

Ensure the main page occupies the entire screen without the need for scrolling

Can someone help me with my Vue app? I need to figure out how to make the start page full screen without any scroll bars in the main window at any scale. The scrollbar should be located within "div class="bottom-center". <script setup> import Comp fr ...

Delete all HTML functionalities

Is there a way to strip HTML functions when using a text area so that the content shows as plain text in a new post (div)? For example, if I type "Hello", I want it to appear as "< b > Hello < b / >", showing the whole code. Here is the code ...

Looking for assistance in implementing specific styling techniques with React

Trying to implement a slider on my React page sourced from a Github repository. The challenge lies in adding the CSS as it is in JS format. Even after incorporating webpack and an npm compiler, the styling seems unrecognized. Any suggestions or solutions ...

Leveraging dynamic slots and dynamic components

I am currently developing a MultiStepForm component and aiming to make it as dynamic as possible. In my Setup.vue component, I have defined a steps array structured like this: const steps = ref([ { label: 'Company', number: 1, ...

Is it more beneficial to enhance the style within a vue.js app or to delegate the task to the website that is

Hello there! I am currently working on my first vue.js app and I could use some assistance in deciding on a design strategy. This app will be integrated into a page of a website that is created using Drupal 8. Both the app and the site will utilize bootstr ...

Can a single camera be utilized for capturing two different scenes?

Hey there! I'm currently working on rendering two different scenes with a camera that moves in sync between the two. Here's what I'm trying to accomplish: I need to display two separate point clouds in two distinct scenes, but I want the ca ...

Generating resized images by manipulating the corners

Is there a way to resize an image inside a div that's already being resized using jQuery? Check out the code on this JSFiddle. $(function(){ //Define your element to resize $('#resizable').resizable({ handles: { ...

Is it possible to retrieve browser history from Google Chrome using Node.js on a Windows operating system?

I'm currently developing a personal electron app for managing my lifestyle. One of the key features is controlling my daily internet browsing through the app. I am aiming to integrate my Chrome history into the electron app. Could someone recommend a ...

Sorry, I am unable to fulfill this request as it requests to paraphrase a code snippet

I encountered an issue while trying to run vue.js 3 with vite https://i.sstatic.net/DGHPu.png Prior to this, I had added nodejs into Variable Environments Despite attempting the following solutions, the error persists: Executing npm cache clear & n ...

problems with using includes() in the array every() method

Hi everyone, I've been spending quite a bit of time trying to find a solution to this problem and I'm hoping someone can help me out. The issue at hand is that I have 2 arrays - one containing multiple words from an address and another built wit ...

Combine the values in the rows over a period of time

I have a set of three times in the format of Minute:Seconds:Milliseconds that I need to add together to get the total time. For example, let's say I have: 0:31.110 + 0:50.490 + 0:32.797, which equals 1:54.397. So how can I achieve this using JavaScr ...

Is it possible to utilize JSX when developing an App using React CDN or the CRA (create-react-app) boilerplate template?

The HTML Code: <div id="app"></div> <script src="https://unpkg.com/react@latest/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@latest/umd/react-dom.develo ...

Manipulating JSON data in JavaScript

Currently delving into learning JSON as required for work purposes... I am attempting to dynamically add and delete records to a JSON object... Can anyone shed some light on why I keep receiving an UNDEFINED message? Here is the code... Appreciate any as ...

Utilizing Vuex and Vue-Router for seamless authentication: Sending user ID from Vuex store to Vue-Router via router-link parameters

Can the ID of the currently logged-in user be passed to the router link's params? I have this piece of code and I am trying to display information on a page based on the params ID. routes.js { path: '/objective/employee/:id', ...

Having trouble saving changes with my Laravel Patch Request - any ideas why?

I was working on a Laravel project for my homework, and I encountered an issue: I have a database with an 'Event' table and multiple relations to this table. Two of them are 'events_news' and 'event_gallery'. While the news u ...

What is a way to utilize Three.js without relying on Node.js, Express, or any build tools?

Objective: Start by importing the necessary modules... Issue: When trying to import jsm files like OrbitControls.js using from 'three';, an error occurs: [Error] TypeError: Module specifier, 'three' does not start with "/", ...

What is the best way to conceal specific series in a HighCharts legend?

In the chart, I currently have 4 series. At the moment, only 2 of them are visible while the other 2 are hidden when the chart first loads. As the user zooms in on the chart, the visibility of the series changes dynamically. I need help figuring out how ...

Leveraging Express and Node.js: The Ultimate Approach to Invoking an External API

I'm brand new to working with Express and Node.js. I'm currently attempting to access an external API in order to populate data on a webpage. Is there a more efficient way to make this API call directly from Express itself (I know that the http m ...