55

I searched and can't figure out how to validate the new reCaptcha, before form submit, along with the validate function of jQuery validation Plugin.

My intent:

    $.validator.addMethod('reCaptchaMethod', function (value, element, param) {
            if (grecaptcha.getResponse() == ''){
                return false;
            } else {
                // I would like also to check server side if the recaptcha response is good
                return true
            }
        }, 'You must complete the antispam verification');


    $("#form").validate({
            rules: {
                name: {
                    required: true,
                    minlength: 2
                },
                email: {
                    required: true,
                    email: true
                },
                reCaptcha: {
                    reCaptchaMethod: true   
                }
            },
            messages: {
                name: "Please fill your name",
                email: "Please use a valid email address"
            },
            submitHandler : function () {
                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }


        });

In a few words: I would like to check server-side, with the remote method, if the user has passed the recaptcha validation BEFORE submitting the form, along with other rules of validation.

I'm able to check the recaptcha AFTER submission (on sendmail.php), but it would be nicer to have the recaptcha validation response along with other fields validation.

The main reason is for a better user experience, having all fields checked at once.

I've managed to achieve this, moving the check inside the submitHandler:

            submitHandler : function () {
                  if (grecaptcha.getResponse() == ''){
                      // if error I post a message in a div
                      $( '#reCaptchaError' ).html( '<p>Please verify youare human</p>' );

                  } else {

                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }

             }

But I don't like this approach, for 2 reasons:

  1. It is just checking if the recaptcha has been filled, not if it's valid, and
  2. User feels like it is a 2 step verification.

In this answer they say it can be done rendering the Recaptcha on a callback, to specify a function call on a successful CAPTCHA response.

I tried to implement that, but I've not been able to use this solution within a rule of the validate() function.

1
  • is it safe to verify recaptcha response from client side? How you are including secret_key? what is the advantage over verifying server side?
    – user557657
    Jul 13, 2016 at 2:08

4 Answers 4

111

I know this question is a bit dated but I was having the same problem and just found the solution. You can do this by adding a hidden field next to the reCaptcha div, like:

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}"></div>
<input type="hidden" class="hiddenRecaptcha required" name="hiddenRecaptcha" id="hiddenRecaptcha">

then in your javascript:

$("#form").validate({
        ignore: ".ignore",
        rules: {
            name: {
                required: true,
                minlength: 2
            },
            email: {
                required: true,
                email: true
            },
            hiddenRecaptcha: {
                required: function () {
                    if (grecaptcha.getResponse() == '') {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        },(...rest of your code)

NOTICE THAT YOU MUST HAVE the ignore: ".ignore" in your code because jquery.validate ignores hidden fields by default, not validating them.

If you want to remove the error message on reCapcha validate add a data-callback to the reCapcha element

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}" data-callback="recaptchaCallback"></div>

And then in your js file add

function recaptchaCallback() {
  $('#hiddenRecaptcha').valid();
};
7
  • nice script.. but how to remove error message on success of captcha ?? thanks in advance
    – Gomzy
    Sep 2, 2016 at 10:09
  • 1
    Just to add, make sure not to place your recaptchaCallback() inside document ready. It is unreachable to the data-callback event. Nov 4, 2016 at 21:19
  • 1
    should the function of the required rule return true when invalid?? it's that ok?
    – Phoenix_uy
    Mar 8, 2017 at 14:20
  • 1
    @Phoenix_uy Sorry for the delay in answering. Yes that is correct, if the captcha answer is invalid you must state that the hidden field is required, in order to display the error
    – FabioG
    Mar 13, 2017 at 17:52
  • 1
    How will the user see an validation error message? I am getting the validation function to run but nothing changes in the UI
    – Jeff
    Jun 22, 2017 at 21:08
17

You can also prevent the form submit in the submitHandler

$("#loginForm").validate({
rules: {
    username: {
        required: true,
        minlength: 6
    },
    password: {
        required: true,
    },
},
submitHandler: function(form) {
    if (grecaptcha.getResponse()) {
        form.submit();
    } else {
        alert('Please confirm captcha to proceed')
    }
}
});
2
  • 1
    Hi Ranjith, I am using the same code but instated for form.submit(); I am using ajax code. How can i use this? Mar 17, 2020 at 14:17
  • @NarenVerma in the place of form.submit(); put your ajax code Aug 25, 2021 at 7:23
5

I've found your solution to be interesting (@FabioG).

But, I've modified it for use a bit by myself and I'm willing to share the code for others to use.

I was working on an interactive form, that validated as you completed steps.

It was used for ordering food. Ergo, the form required verification and activation of the register button and it is using the latest reCaptcha to date (5/12/2016).

Also, this code handles expired reCaptcha, server-side verification via ajax (though not included - if someone needs it to feel free to comment on my answer and I'll edit it accordingly).

Let's get started.

The HTML code:

<form id="registerForm" method="get" action="">
<fieldset class="step-1">
<h4>Step One:</h4>
<span class="clock">Register under one minute!</span>
<label for="email-register" class="label">E-mail*</label>
<input id="email-register" name="email-register" type="email" value="" autocomplete="off"/>

<label for="password-register" class="label">Password*</label>
<input id="password-register" name="password-register" type="password" value="" autocomplete="off"/>

<div class="g-recaptcha" data-sitekey="6LeS4O8SAAAAALWqAVWnlcB6TDeIjDDAqoWuoyo9" data-callback="recaptchaCallback" data-expired-callback="recaptchaExpired" style="margin-top: 3rem;"></div>
<input id="hidden-grecaptcha" name="hidden-grecaptcha" type="text" style="opacity: 0; position: absolute; top: 0; left: 0; height: 1px; width: 1px;"/>
</div>
</fieldset>
<fieldset class="step-2">
<h4>Step two:</h4>
<span class="notice">All fields with a sign are required!*</span>
<label for="first-name" class="label">First Name*</label>
<input name="first-name" id="first-name" type="text" value="" />

<label for="last-name" class="label">Last Name*</label>
<input name="last-name" id="last-name" type="text" value="" />

<label for="address" class="label">Address*</label> 
<input name="address" id="address" type="text" value=""/>

<label for="entrance" class="label">Entrance</label>    
<input name="entrance" id="entrance" type="text" value=""/>

<label for="apartment-number" class="label">Apartment #</label>
<input name="apartment-number" id="apartment-number" type="text" value="" />

<label for="inter-phone" class="label">Interphone</label>           
<input name="inter-phone" id="inter-phone" type="text" value=""/>

<label for="telephone" class="label">Mobile Number*</label>
<input name="telephone" id="telephone" type="text" value="" />

<label for="special-instructions" class="label">Special Instructions</label>    
<textarea name="special-instructions" id="special-instructions"></textarea>
<div>
</fieldset>
<button class="button-register" disabled>Register</button>
</form>

So as you can see, the button for submission (".button-register") is initially disabled.

You can only enable it by filling the mandatory (*) fields.

Please, keep in mind that I didn't include any CSS. The form is on a bare minimum and is just for educational purposes.

Few things that differ from @FabioG, the answer is:

There is no need to hide the element or use the ".ignore". I've hidden it with inline CSS.

There is a response callback for successful reCaptcha and expired reCaptcha.

So, if your reCaptcha expires while filling out the form it will make it invalid and the button will be disabled again.

As well, the form uses an input field (the hidden input field) to pass the information onto AJAX(PHP later on) and verify it server-side (It is a potential security risk, I covered it more at the end of the text).

Let's move on to JavaScript/jQuery.

JavaScript/jQuery:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
function recaptchaCallback() {
    var response = grecaptcha.getResponse(),
        $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val(response);
    console.log(jQuery("#registerForm").valid());
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}

function recaptchaExpired() {
    var $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val("");
    var $button = jQuery(".button-register");
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}
function submitRegister() {
  //ajax stuff
}
(function ($, root, undefined) {
    $(function () {
        'use strict';
        jQuery("#registerForm").find("input").on("keyup", debounce(function() {
          var $button = jQuery(".button-register");
          if (jQuery("#registerForm").valid()) {
            $button.attr("disabled", false);
          }
          else {
            $button.attr("disabled", "disabled");
          }
        }, 1000));
        jQuery("#registerForm").validate({
          rules: {
            "email-register": {
              required: true,
              email: true
            },
            "password-register": {
              required: true,
              minlength: "6"
            },
            "first-name": "required",
            "last-name": "required",
            address: "required",
            telephone: "required",
            "hidden-grecaptcha": {
              required: true,
              minlength: "255"
            }
          },
          messages: {
            "email-register": "Enter valid e-mail address",
            "password-register": {
              required: "Enter valid password",
              minlength: "Password must be bigger then 6 chars!"
            },
            "first-name": "Required!",
            "last-name": "Required!",
            address: "Required!",
            telephone: "Required!"
          },
          submitHandler: submitRegister
        });
    }); 
})(jQuery, this);

As you can see here, there are a few functions: recaptchaCallback() and recaptchaExpired().

recaptchaCallback() that is embeded via the data attribute data-callback, uses the grecaptcha.getResponse() to see if the reCaptcha is validated, if so it enters the token to the hidden input field and asks for re-validation via the jQuery("#registerForm).validate();.

However, if the reCaptcha expires in the meanwhile it will use the assigned function in the "data-expired-callback", to remove the token from the input field and ask for re-validation again which will fail because the field is empty. This is achieved with the function recaptchaExpired().

Later in the code, you can see that we added a jQuery keyup function, to check for re-validation and see if the user has passed on the required information to the input fields. If the information and the field validate successfully the keyup function will enable the Register button.

Also, I've used a debounce script (tnx, David Walsh) on keyup. So it doesn't cause browser lag. Since, there would be a lot of typing.

But, keep in mind if a user decides to circumvent the reCaptcha he can always just enter the "255" character long string to the input field. But, I've gone a step further and made an AJAX verification server-side to confirm the reCaptcha. Though, I haven't included it in the answer.

I think this code is a marginal improvement on the previous answer. If you have any questions or need the AJAX/PHP code feel free to comment. I'll supply it when I can.

Heres the codepen as well: reCaptcha with jQuery.validation

You can find all the information regarding the reCatpcha data-attributes and functions in their API here: reCaptcha API

Hope it helped someone!

Regards,

1
  • this works, but it is a bit awkward for the user, as your .on("keyup" call prompts you with validation errors before you get to finish filling out the form. It would be much nicer if the prompts would only show up after clicking Register and the form is invalid.
    – MeSo2
    May 17, 2022 at 16:58
2

I struggled with this one today and ended up going with:

<form onsubmit="return $(this).valid() && grecaptcha.getResponse() != ''">

Which just feels like the simplest way to do it. Someone is bound to complain about putting js inline like that but I'm ok with it.

3
  • 2
    the problem is that I would like to integrate the captcha validation with jQuery .Validate() fuction, so I could present to user a single list of errors in filling fields. Sorry but I don't understand how to achieve that using your solution?
    – bluantinoo
    May 22, 2015 at 17:43
  • you can achieve it by calling a function . like <form onsubmit="return validateForm()"> then in script tag u can call this and can do your stuff function validateForm(){ //do the code here } Jun 15, 2021 at 7:02
  • it helps me and thanks @pguardiario for this pretty solution Jun 15, 2021 at 7:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.