Dan Dan - 2 months ago 27
jQuery Question

reCAPTCHA field on page that is loaded through AJAX doesn't load. Suggestions?

Live Examples:



When I view the source page everything works fine, but when I load through an AJAX request, in the place where the reCAPTCHA should be, I see...

<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>


Obviously, this does nothing unless my user has JS disabled. During this process no errors are thrown.

Viewing the code on the non-AJAX-requested pace, I see...

<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX"></script>

<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>


Note the additional line at the top of the script that addresses users with JS enabled.

So I guess the question is two-fold. WTF is happening and how can I fix it?

I've found some vague mention of this issue, but no decent answers. I found some mention of the reCAPTCHA API using
document.write
, but I don't know if that's valid. If I've overlooked something obvious, please feel free to point it out.

Per request, the AJAX call is...

$(document).ready(function() {
$.get('/inc/email.php',
function(data){
console.log('Get success!');
$('#email-form').html(data);
console.log('Get added to #email-form!');
$('#email-form form').submit( function(){
$.ajax({
type: "POST",
url: "/inc/email.php",
data: $('#email-form form').serialize(),
success: function() {
console.log('Submit success!');
$('#email-form').html(data);
}
});
return false;
});
}
);
});


What I've tries so far:


Answer

Explanation:

The reason this breaks when doing it with AJAX, is because jQuery strips out any script tags from your HTML before appending it to the DOM, and evaluates it in the global context. It does not insert it into the DOM together with the rest of your HTML.


In your code:

The culprit in your code is this line:

$('#email-form').html(data);

You're taking the raw HTML string recieved from the server, and appending it to the DOM. However, jQuery first removes the script tag from your data variable, and evaluate that in the global context.

Since the recaptcha.js script uses document.write to add its stuff to the DOM, it breaks; document.write has to run exactly where you want it to output the HTML.


Solutions:

There are 2 possible solutions.

Solution #1:

Instead of relying on jQuery completely, you could insert the script tag yourself using vanilla JavaScript, which will cause the document.write to run where you want it to - right there in the DOM:

success: function() {
    var form = $('#email-form')[0],
        script = $('<script src="http://www.google.com/recaptcha/api/challenge?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" />')[0];

    form.appendChild(script);
}

Note the [0] at the end of those lines. They're used to access the underlying native DOM object, so that we can use the DOM's native appendChild.

Solution #2:

Instead of loading the data through AJAX, consider putting it in a page of its own, and then just insert an iframe into your page:

success: function() {
    $('#email-form').html('<iframe src="path/to/reCAPTCHA/page.html" />');
}