Is there a way to invoke a function once grecaptcha.execute() has completed running, but in response to a particular event?

Presently, the JavaScript function grecaptcha.execute is triggered on page load, as shown in the first example below. This means that the reCAPTCHA challenge occurs as soon as the page loads. A more ideal scenario would be to trigger it when the form submit button is clicked instead. I attempted this by moving the execution into the submit event (as shown in the second JS example) and placing the axios function within a promise. However, it seems that the form is being submitted before the grecaptcha.execute completes its execution.

What am I missing here? This is my initial encounter with promises, so perhaps I don't quite understand how they operate? Is there a better solution for this issue? Or could it be something else entirely?

HTML

<head>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" defer></script>
</head>

JS

const form = document.querySelector('#subscribe');
let recaptchaToken;
const recaptchaExecute = (token) => {
    recaptchaToken = token;
};


const onloadCallback = () => {
    grecaptcha.render('recaptcha', {
        'sitekey': 'abcexamplesitekey',
        'callback': recaptchaExecute,
        'size': 'invisible',
    });
    grecaptcha.execute();
};

form.addEventListener('submit', (e) => {
    e.preventDefault();
    const formResponse = document.querySelector('.js-form__error-message');
    axios({
        method: 'POST',
        url: '/actions/newsletter/verifyRecaptcha',
        data: qs.stringify({
            recaptcha: recaptchaToken,
            [window.csrfTokenName]: window.csrfTokenValue,

        }),
        config: {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
        },
    }).then((data) => {
        if (data && data.data.success) {
            formResponse.innerHTML = '';
            form.submit();
        } else {
            formResponse.innerHTML = 'Form submission failed, please try again';
        }
    });
}

JS

const onloadCallback = () => {
    grecaptcha.render('recaptcha', {
        'sitekey': 'abcexamplesitekey',
        'callback': recaptchaExecute,
        'size': 'invisible',
    });
};

form.addEventListener('submit', (e) => {
    e.preventDefault();
    const formResponse = document.querySelector('.js-form__error-message');
    grecaptcha.execute().then(axios({
        method: 'POST',
        url: '/actions/newsletter/verifyRecaptcha',
        data: qs.stringify({
            recaptcha: recaptchaToken,
            [window.csrfTokenName]: window.csrfTokenValue,
        }),
        config: {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
        },
    })).then((data) => {
        if (data && data.data.success) {
            formResponse.innerHTML = '';
            form.submit();
        } else {
            formResponse.innerHTML = 'Form submission failed, please try again';
        }
    });
}

Answer №1

Utilizing a web service to have a universal method across all pages has been my preferred approach. It is crucial to note the necessity of returning false and triggering a post back upon the completion of the ajax request.

<script type="text/javascript>

   function VerifyCaptcha()
    {
        grecaptcha.ready(function () {
            grecaptcha.execute('<%#RecaptchaSiteKey%>', { action: 'homepage' }).then(function (token) {
            $.ajax({
                type: "POST",
                url: "../WebServices/Captcha.asmx/CaptchaVerify", 
                data: JSON.stringify({ 'captchaToken' : token }),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (response) {
                    __doPostBack('<%= RegisterButton.UniqueID%>', '');
                    //console.log('Token verification successful');
                },
                failure: function (response) {                     
                    //alert(response.d);
                }
                });
            });
       });

       return false;
    }

</script>

Answer №2

To address this issue, I made a simple change by converting the submit button into a basic button and managing everything within a JavaScript function:

@Html.HiddenFor(model => model.ReCaptchaToken);

<input type="button"
        value="Submit"
        onclick="onSubmit()"
/>

The 'then()' method waits for the token, places it in a hidden field, and only then proceeds to manually submit the form:

<script>
    if (typeof grecaptcha == 'object') { // This may be undefined behind certain firewalls
        grecaptcha.execute('@Config.ReCaptchaSiteKey', { action: 'register' }).then(function (token) {
            window.document.getElementById('ReCaptchaToken').value = token;
            $('form').submit();
        });
    } else {
        window.document.getElementById('ReCaptchaToken').value = -1;
        $('form').submit();
    }
</script>

Keep in mind: @Html.HiddenFor is specific to MVC - you may not need that. $('form') pertains to JQuery - although you can also use getElementById instead.

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

How can you locate the position of identified text on a webpage to accurately place the mouse cursor there?

When browsing a webpage in my web browser (preferably Firefox), I have the ability to search for a specific text "abc" using ctrl+f. Once found, I need to move my mouse cursor to another relative position on the page and click. Unfortunately, the necessar ...

Retrieve the character count of the text within a dynamically created div using AJAX

I have a .php file containing an array of strings. One of these strings is fetched by my page and inserted into an empty div named post. However, when I try to determine the length of the string in the post, I always receive the error: Uncaught TypeErro ...

What is the process by which photoswipe applies styles to blur an image upon clicking the share button?

If you want to see an example, check out this link: http://codepen.io/dimsemenov/pen/gbadPv By clicking on the Share button, you'll notice that it blurs the image (and everything else). Despite inspecting it closely, I still can't seem to figu ...

What exactly does the statement if(item.some((item) => !item.available) represent in typescript?

Can you explain the meaning of if(item.some((item) => !item.available))? While looking at some code randomly, I came across this snippet: if(item.some((item) => !item.available){ } I'm curious about what it signifies. Can you elaborate on it? ...

Tips for passing a parameter (such as an ID) through a URL using ng-click to display a subdocument belonging to a particular user in

I am looking to retrieve specific user subdocument data on a separate page by passing the id parameter in a URL using ng-click in AngularJS. <tr ng-repeat="register in registerlist | filter:searchText"> <td>{{$index+1}}</td> <td&g ...

Having trouble with adding a listener or making @click work in VueJS?

Apologies for my limited experience with Vue. I am currently facing an issue where one of my click functions is not working as expected for multiple elements. The click event is properly triggered for the #app-icon element. However, the function is not be ...

EJS unable to display template content

I am having an issue with rendering a template that contains the following code block: <% if(type === 'Not Within Specifications'){ %> <% if(Length !== undefined) { %><h5>Length: <%= Length %> </h5> <% ...

What is the best way to conceal an image tag depending on an ajax response?

What is the correct jQuery statement to replace the "//Needed incantation" comments below so that the image tags are displayed or hidden based on the AJAX responses? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR ...

Modify the content in the v-navigation-drawer upon clicking

I am currently working on a project with a v-navigation-drawer and two buttons. The first button is designed to open the drawer, while the second one should change the content of the drawer without closing it. I want the content to update instantly without ...

"Troubleshooting the issue of jQuery failing to set data

Although it seems straightforward, I am puzzled as to why this code is not functioning properly. The selector is accurate, but for some reason the .faqContent div is not being updated with the data-height attribute. $('.faqItem .faqContent').eac ...

Ways to navigate to a different page using HTML response from an AJAX request

After receiving an HTML document as a response from an AJAX call, I need to create a redirection page using this HTML response. Can anyone provide guidance on how to achieve this? ...

Oops! The provided value for the argument "value" is not a valid query constraint. Firestore does not allow the use of "undefined" as a value

I encountered an error while exporting modules from file A and importing them into file B. When running file B, the error related to Firebase Cloud Firestore is displayed. const getMailEvents = (startTime, endTime) => { serverRef = db.collection("Ma ...

In the Rails environment, it is important to verify that the data sent through $.post method in jQuery is correctly

I’m facing an issue with my jQuery script when trying to post data as shown below: $.post({ $('div#location_select').data('cities-path'), { location_string: $('input#city_name').val() }, }); Although this code work ...

Several buttons, each requiring to show distinct text

Currently, I am attempting to enhance an existing project that was graciously created for me. I must admit, I am quite new to this, so please be patient with me! In my project, there are 9 buttons, each triggering the display of a different image upon bei ...

dirpagination fails to display all rows in the dataset

I've been working on creating tables with 3 divs, as shown in the link below:- https://github.com/anirbanmishra/congress.php/blob/master/web_test Additionally, I have a javascript file available here:- https://github.com/anirbanmishra/congress.php/bl ...

Why is it necessary to click twice with AjaxUpload?

Utilizing AjaxUpload.2.0.min.js, the following code facilitates file uploads to the server. An issue arises where multiple clicks on the “Add File” button are required for the OS window (for selecting the file to upload) to appear, rather than just on ...

Learn how to successfully carry on with event.preventdefault in JavaScript

Is there a way to create a modal that prompts the user to confirm if they want to leave the page without committing changes? These changes are not made within a <form> element, but rather on a specific object. I've attempted to use both $route ...

Determine the estimated download duration using the $http protocol

I am experiencing an issue with a function that calculates the time it takes to download a text file (3MB in size) from my server. While it works well for single requests, when I attempt to run multiple requests simultaneously, the time spent waiting for a ...

Why is my ASP.NET checkbox losing its value after postback because of a JavaScript/jQuery array?

I'm facing an issue with a simple asp:RadioButtonList nested inside a form tag where it's not retaining its value on postback. Here's the code snippet: <form runat="server"> <div class="Form"> <span class="FirstField"> ...

What could be causing my function to fail <object>?

Within index.php, I am calling the function twice, which includes chart.html. index.php chart_line($valuesNight); //first call chart_line($valuesEvening); //second call ?> <?php function chart_line($jsonDataSource){ ?> < ...