Not able to parse JSON response from Weather Underground API - ajax

I am trying to create a simple weather page. I want to retrieve coordinates of the user location and subsequently the weather information of location from Weather Underground API. I am able to get to see the JSON response for my coordinates. However, i am having problem parsing JSON using AJAX function and show it on HTML. Below is my code
HTML:
<div class="container-fluid text-center">
<body>
<div id="forecast">
<h1>Weather at <span id="location"> </span></h1>
<div id="imgdiv">
<img id="img" src=""/>
</div>
<p>It is currently <span id="temp"> </span>°C with <span id="desc"> </span></p>
<p>Wind: <span id="wind"></span></p>
</body>
</div>
JQuery;
var Geo={};
var temp_f
//var key = ‘4d6eb96f1aa092b2’;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success,error);
}
else {
alert('Geolocation is not supported');
}
function error() {
alert("That's weird! We couldn't find you!");
}
function success(position) {
Geo.lat = position.coords.latitude;
Geo.lng = position.coords.longitude;
Geo.url = "http://api.wunderground.com/api/4d6eb96f1aa092b2/forecast/geolookup/conditions/q/" + Geo.lat + "," + Geo.lng + ".json";
$.ajax({
url : Geo.url,
dataType : "json",
success : function(url) {
location = url['location']['city'];
temp_f = url['current_observation']['temp_f'];
$("#temp").html(temp_f);
}
});
}
I get location and temp_f value as undefined. I referred very similar post Weather Underground API with Ajax yet not able to figure out what is the problem ? I am new this so please excuse if am missing something basic.

It works fine for me check: https://jsfiddle.net/jigarb1992/q1w8usq9/
The problem I found in your code is may be here location = url['location']['city'];, the location in javascript will redirect you to given location.
Try the code I have do changes in jsfiddle

Related

Getting response back from server but .html not sowing anything in wordpress ajax

On click I'm sending the id as data and then using query showing the name of user from WordPress database. I'm getting the response back from server but It is not adding when try to use .html(response).May be this is something to do with permission ?Like only admin can use the response?
If that's the case what I can do.
This is the ajax function:
function get_user_id() {
let get_current_user_id =jQuery(this).attr('id');
cur_user = '<?php echo get_current_user_id() ;?>';
var postdata_name = {action: "incoming_user_name_ajax_call",
param_user_to_chat: get_current_user_id,};
jQuery.post(ajaxurl, postdata_name, function (response) {
jQuery("#name-incoming-user").html(response);});
}
This is the function in functions.php
add_action("wp_ajax_incoming_user_name_ajax_call", "incoming_user_name_ajax_call_fn");
add_action("wp_ajax_nopriv_incoming_user_name_ajax_call", "incoming_user_name_ajax_call_fn");
function incoming_user_name_ajax_call_fn() {
global $wpdb;
$param_user_to_chat=isset($_REQUEST['param_user_to_chat'])?trim($_REQUEST['param_user_to_chat']):"";
if (!empty($param_user_to_chat)) {
$posts = $wpdb->get_results("SELECT distinct(display_name) FROM wp_users where
ID=$param_user_to_chat");
echo $posts[0]->display_name;
}
wp_die();}
Posting the HTML as well for everyone who want to know what jQuery(this).attr('id'); is doing. It is getting id "4" or "2" depending on click.
<div id="target">
<div class="user-list-hide" id="user-hide" style="display: block;">
<div id="4"><span>Jason Bradley</span>/div>
<div id="2"><span>John Saddington</span></div>
</div>
</div>
There was issue in your jquery code i.e : the way you were calling your get_user_id() function here you have use wrong selector to get your inner divs . So, to make it work change :
jQuery("#target").on("click", "div", get_user_id);
to
jQuery("#user-hide").on("click", "div", get_user_id);

Assigning HTML content to a var in Google Spreadsheet Script

I'm trying to execute an automail through a script in Google Spreadsheet to mail all my clients at a single time. But every time I'm trying to run the script it says that I've incorrectly assigned the HTML content to a variable.
The script code for assigning the value was :
function sendMail(){
var name = 1;
var email = 2;
var userEmail = 3;
var password = 4;
var emailTemp = HtmlService.createTemplateFromFile("MailApp");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Copy of OneDrive Cloud Storage");
var data = ws.getRange("B2:E" + ws.getLastRow()).getValues();
data.forEach(function(row){
emailTemp.name = row[name];
emailTemp.userEmail = row[userEmail];
emailTemp.password = row[password];
emailTemp.email = row[email];
var htmlMessage = emailTemp.evaluate().getContent();
GmailApp.sendEmail(
row[email],
"OneDrive 5TB Storage",
"Your email doesn't support HTML.",
{name: "AutoMail by Shovon", htmlBody: htmlMessage}
);
});
}
An error was in the line: var htmlMessage = emailTemp.evaluate().getContent();
The error message says :
I'm also attaching the HTML code:
<html>
<head>
<base target="_top">
</head>
<body>
<p>Dear <b> <?= name ?>, </b> </p>
<p>I received your <b>OneDrive 5TB Cloud Storage</b> request yesterday. I'm really very sorry for being so late as I had some personal things to do.</p>
<p>But the good news is I've successfully created the following <b>OneDrive Business Account</b> for you: </p>
<p> User email:<b> <u><? = userEmail?> </u> </b> <br>
Password: <b> <?= password?> </b> </p>
<p> Please login to this <b> Microsoft</b> account as soon as possible and set up 2 steps verification method by using your own email address(e.g. <b> <u> <?= email ?> </u> </b>).</p>
<p>To login <b> <u> click here</u></b>.</p>
<p>Yours,<br>
<b>Md. Shahariar Shovon</b></p>
</body>
</html>
Please help me solving this issue.
You have a typo.
<? = userEmail?>
should be
<?= userEmail?>
So the app script tries to eval javascript code "= userMail" instead of simple "userMail" which is apparently invalid
You don't need HtmlService, as "The HTML service lets you serve web pages that can interact with server-side Apps Script functions." and that is its use case.
So just create the HTML using JavaScript and then place it into the body. For example, picture this in your for loop.
const infoObj = {
name: row[name],
email: row[userEmail]
}
const emailBody = createEmailBody( infoObj );
const params = {
name: "AutoMail by Shovon",
htmlBody: emailBody.html
}
GmailApp.sendEmail(infoObj.email, subject, emailBody.plain, params);
// here you can create your html body
function createEmailBody( info ) {
return {
plain: `Hi ${info.name}, this is your ${info.email}`,
html: `<div>Hi ${info.name}, this is your email ${info.email} </div>`
}
}

Inline javascript is getting stripped off from the AJAX response by Prototype JS Ajax.Request method

I am working on a Magento store trying to code a widget's javascript layer with the help of Prototype js framework.
In my grid.js file AJAX call is setup like that:
loadTabContent: function(tab, tabType){
if(tab === undefined || tabType === undefined){
return this;
}
entityId = tab.id.split('-')[3];
request = new Ajax.Request(
this.tabContentLoadUrl,
{
method:'get',
onSuccess: this.onTabContentLoad.bind(tab),
onFailure: this.ajaxFailure.bind(this),
evalJS: true,
parameters: {
id: entityId,
type: tabType
}
}
);
}
Below is the success handler:
onTabContentLoad: function(transport){
if(transport && typeof transport.responseText !== undefined){
try{
response = transport.responseText;
}catch (e) {
console.log('PARSE ERROR', e);
response = {};
}
entityId = this.id.split('-')[3];
tabType = this.id.split('-')[1];
if(response && $('tab-' + tabType + '-' + entityId + '-contents')){
$('tab-' + tabType + '-' + entityId + '-contents').update(response);
}
}
},
The content for the div is getting updated correctly by the AJAX call but there is some inline JS in response which is not working.
I can't even see that javascript snippet in Elements tab(chrome developer tool)
Below is the code that handles the AJAX request on server side:
public function renderTabContentAction()
{
$entityId = Mage::app()->getRequest()->getParam('id');
if( ! $entityId){
$this->getResponse()->setHeader('HTTP/1.0', '400', true);
$this->getResponse()->setBody('Invalid parameters provided.');
}
$tabType = Mage::app()->getRequest()->getParam('type');
if( ! $tabType){
$this->getResponse()->setHeader('HTTP/1.0', '400', true);
$this->getResponse()->setBody('Invalid parameters provided.');
}
Mage::register('current_entity_id', $entityId);
Mage::register('current_tab_type', $tabType);
$tabHtml = $this->_getTabsHtml($entityId, $tabType);
$this->getResponse()->setHeader('HTTP/1.0', '200', true);
$this->getResponse()->setBody($tabHtml);
}
Below is the response that gets passed to onTabContentLoad AJAX handler:
<div class="vertical-tabs">
<div class="tabs">
<div class="tab" id="tab-vertical-137-2441">
<input type="radio" id="label-vertical-product-tab-137-2441" name="product-tab-group-137">
<label class="tabs-label" for="label-vertical-product-tab-137-2441">PG-10ml</label>
<div class="content" id="tab-vertical-137-2441-contents">
</div>
</div>
<div class="tab" id="tab-vertical-137-2442">
<input type="radio" id="label-vertical-product-tab-137-2442" name="product-tab-group-137">
<label class="tabs-label" for="label-vertical-product-tab-137-2442">PG-15ml</label>
<div class="content" id="tab-vertical-137-2442-contents">
</div>
</div>
</div>
</div>
<script type="text/javascript">
bulkOrderGrid.initVerticalTabs();
bulkOrderGrid.activateTab('2441', 'VERTICAL');
</script>
You can see that the SCRIPT tags are there in the response. Its just when the content gets updated using Element.update function it strips off the SCRIPT tags. That's what I can understand so far.
NOTE:
I have also used Ajax.Updater along with evalScripts:true and Ajax.Request along with evalJS:true.
Got stuck here. Any help would be much appreciated.
UPDATES:
Since I am using Element.update function to refresh the section. The source of the problem is this part of the code in prototype.js around line no. 2048. I can see its getting executed in js debugger. It does evaluates the js code but also removes the SCRIPT tags from the source. Commenting out stripScripts works fine.
else {
element.innerHTML = content.stripScripts();
}
content.evalScripts.bind(content).defer();
I think your problem is that
the Ajax response is passed through String#evalScripts() but the context is not the global context so instead of your script block do this
<script type="text/javascript">
window.bulkOrderGrid.initVerticalTabs();
window.bulkOrderGrid.activateTab('2441', 'VERTICAL');
</script>
if that doesnt fix it - than you can directly run transport.responseText.evalScripts() but you still need the window. in your script block to resolve the scope of the variables.
You are correct Element.update() remove script tag. you should use
Element.innerHTML

nodejs cannot serve static files - downloads them

I am playing around with nodejs, creating a simple server, also handles some ajax. When I go to localhost:4000 the page does not render, instead an empty file is automatically downloaded. It is named "download file", zero byte and no extension.
I think my client and my server are really simple. Sorry for the generic question but I fail to understand why this is happening.
Thanks in advance
Client - a simple form and a XHR that sends json-type data
<html>
<head> <title>Chatrooms</title> </head>
<body>
<form id="fruitform" method="post" action="/">
<div class="table">
<div class="row">
<div class="cell label">Bananas:</div>
<div class="cell"><input name="bananas" value="2"/></div>
</div>
<div class="row">
<div class="cell label">Apples:</div>
<div class="cell"><input name="apples" value="5"/></div>
</div>
<div class="row">
<div class="cell label">Cherries:</div>
<div class="cell"><input name="cherries" value="20"/></div>
</div>
<div class="row">
<div class="cell label">Total:</div>
<div id="results" class="cell">0 items</div>
</div>
</div>
<button id="submit" type="button">Submit Form</button>
</form>
<div id="results"></div>
<div id="de"></div>
</body>
</html>
<script type="text/javascript">
document.getElementById("submit").onclick = handleButtonPress;
function handleButtonPress(e) {
e.preventDefault();
var formData = "";
//gather all input values in a json type string
var inputElements = document.getElementsByTagName("input");
for (var i = 0; i < inputElements.length; i++) {
formData += inputElements[i].name + "=" + inputElements[i].value + "&";
}
formData = formData.slice(0, -1);
var hr = new XMLHttpRequest();
hr.open("POST", "/formHandler", true);
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
document.getElementById("results").innerHTML = hr.responseText;
}
}
hr.send(formData);
}
</script>
Server
//dependencies
var http = require ('http');
var fs = require ('fs');
var path = require ('path');
var mime = require ('mime');
var qs = require('querystring');
//this is the http server
var server = http.createServer(function (request, response){
var filePath = false;
if (request.url == '/'){
filePath='public/index.html';//default static file
}
if (request.url == '/formHandler'){//handle XHR
if (request.method=="POST"){
var rrr="rrr";
response.writeHead(200,{"content-type":"text/plain"});
response.write(rrr);
response.end(rrr);
}
}
else{
filePath='public'+request.url;//set relative file path
}
var absPath = './'+filePath;
serveStatic(request, response, cache, absPath);//serve the static file
});
server.listen(4000, function(){
console.log("Chatrooms server on port 4000");
}
);
//read static files
function serveStatic(request, response,cache, absPath){
fs.readFile(absPath, function(err, data){
sendFile(request, response, absPath, data);
})
}
//serve file data
function sendFile(request, response, filePath, fileContents){
response.writeHead(
200,{"content-type":mime.lookup(path.basename(filePath))}
);
response.end(fileContents);
}
UPDATE
If I remove the following part from the server, it works fine. Still cannot understand what is going on
if (request.url == '/formHandler'){
console.log("inside ajax if");
console.log("inside formPro");
if (request.method=="POST"){
console.log("inside second ajax if");
var rrr="rrr";
response.writeHead(200,{"content-type":"text/plain"});
response.write(rrr);
response.end(rrr);
console.log("finished sending rrr");
}
}
Most likely fs.readFile is returning an error, which you are ignoring.
When serving static files you should not read the whole thing into memory like this. The whole point of Node.JS is to keep I/O freely flowing.
Use fs.createReadStream(filePath).pipe(response) instead, although you will need to add an error listener, or run within a domain.
UPDATE
Bugs abound - you don't return from any cases and just carry through to the next one.
i.e. You can end up calling both request.end() and serveStatic.
I would recomend you to use node express module http://expressjs.com/
which will allow you to write custom template renderer as well as static pages including css and js image files
simply install express using
npm -g install express
Following up on #Dickens answer here is the basic express app that handles your form and all static files in ./public/
//dependencies
var http = require ('http');
var express = require('express'); // npm install --save express
var app = express();
app.use(express.static(__dirname+'/public'));
app.post('/formHandler', function(req, res){
res.status(200).send('rrr');
})
var server = http.createServer(app);
server.listen(4000, function(){
console.log("Chatrooms server on port 4000");
});
// Test with:
// curl -vX POST http://localhost:4000/formHandler
// curl -vX GET http://localhost:4000/index.html

How do I show multiple recaptchas on a single page?

I have 2 forms on a single page. One of the forms has a Recaptcha displaying all the time. The other should display a Recaptcha only after a certain event such as maxing out login attempts. So there are times when I would need 2 Recaptchas to appear on the same page. Is this possible? I know I could probably use a single one for both, but the way I have the layout, I would much prefer to have 2. Thanks.
Update: well I guess it may not be possible. Can anybody recommend another capture library to use side by side with reCaptcha? I really want to be able to have 2 captchas on the same page.
Update 2: What if I put each form in an iframe? Would this be an acceptable solution?
With the current version of Recaptcha (reCAPTCHA API version 2.0), you can have multiple Recaptchas on one page.
There is no need to clone the Recaptcha nor try to workaround the problem. You just have to put multiple <div> elements for the Recaptchas and render the Recaptchas inside them explicitly.
This is easy with the Google Recaptcha API. Here is the example HTML code:
<form>
<h1>Form 1</h1>
<div><input type="text" name="field1" placeholder="field1"></div>
<div><input type="text" name="field2" placeholder="field2"></div>
<div id="RecaptchaField1"></div>
<div><input type="submit"></div>
</form>
<form>
<h1>Form 2</h1>
<div><input type="text" name="field3" placeholder="field3"></div>
<div><input type="text" name="field4" placeholder="field4"></div>
<div id="RecaptchaField2"></div>
<div><input type="submit"></div>
</form>
In your Javascript code, you have to define a callback function for Recaptcha:
<script type="text/javascript">
var CaptchaCallback = function() {
grecaptcha.render('RecaptchaField1', {'sitekey' : '6Lc_your_site_key'});
grecaptcha.render('RecaptchaField2', {'sitekey' : '6Lc_your_site_key'});
};
</script>
After this, your Recaptcha script URL should look like this:
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
Or instead of giving IDs to your Recaptcha fields, you can give a class name and loop these elements with your class selector and call .render().
Simple and straightforward:
Create your Recaptcha fields normally with this:
<div class="g-recaptcha" data-sitekey="YOUR_KEY_HERE"></div>
Load the script with this:
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
Now call this to iterate over the fields and create the Recaptchas:
<script type="text/javascript">
var CaptchaCallback = function() {
jQuery('.g-recaptcha').each(function(index, el) {
grecaptcha.render(el, {
'sitekey' : jQuery(el).attr('data-sitekey')
,'theme' : jQuery(el).attr('data-theme')
,'size' : jQuery(el).attr('data-size')
,'tabindex' : jQuery(el).attr('data-tabindex')
,'callback' : jQuery(el).attr('data-callback')
,'expired-callback' : jQuery(el).attr('data-expired-callback')
,'error-callback' : jQuery(el).attr('data-error-callback')
});
});
};
</script>
This answer is an extension to #raphadko's answer.
If you need to extract manually the captcha code (like in ajax requests) you have to call:
grecaptcha.getResponse(widget_id)
But how can you retrieve the widget id parameter?
I use this definition of CaptchaCallback to store the widget id of each g-recaptcha box (as an HTML data attribute):
var CaptchaCallback = function() {
jQuery('.g-recaptcha').each(function(index, el) {
var widgetId = grecaptcha.render(el, {'sitekey' : 'your code'});
jQuery(this).attr('data-widget-id', widgetId);
});
};
Then I can call:
grecaptcha.getResponse(jQuery('#your_recaptcha_box_id').attr('data-widget-id'));
to extract the code.
A similar question was asked about doing this on an ASP page (link) and the consensus over there was that it was not possible to do with recaptcha. It seems that multiple forms on a single page must share the captcha, unless you're willing to use a different captcha. If you are not locked into recaptcha a good library to take a look at is the Zend Frameworks Zend_Captcha component (link). It contains a few
This is easily accomplished with jQuery's clone() function.
So you must create two wrapper divs for the recaptcha. My first form's recaptcha div:
<div id="myrecap">
<?php
require_once('recaptchalib.php');
$publickey = "XXXXXXXXXXX-XXXXXXXXXXX";
echo recaptcha_get_html($publickey);
?>
</div>
The second form's div is empty (different ID). So mine is just:
<div id="myraterecap"></div>
Then the javascript is quite simple:
$(document).ready(function() {
// Duplicate our reCapcha
$('#myraterecap').html($('#myrecap').clone(true,true));
});
Probably don't need the second parameter with a true value in clone(), but doesn't hurt to have it... The only issue with this method is if you are submitting your form via ajax, the problem is that you have two elements that have the same name and you must me a bit more clever with the way you capture that correct element's values (the two ids for reCaptcha elements are #recaptcha_response_field and #recaptcha_challenge_field just in case someone needs them)
I know this question is old but in case if anyone will look for it in the future. It is possible to have two captcha's on one page. Pink to documentation is here: https://developers.google.com/recaptcha/docs/display
Example below is just a copy form doc and you dont have to specify different layouts.
<script type="text/javascript">
var verifyCallback = function(response) {
alert(response);
};
var widgetId1;
var widgetId2;
var onloadCallback = function() {
// Renders the HTML element with id 'example1' as a reCAPTCHA widget.
// The id of the reCAPTCHA widget is assigned to 'widgetId1'.
widgetId1 = grecaptcha.render('example1', {
'sitekey' : 'your_site_key',
'theme' : 'light'
});
widgetId2 = grecaptcha.render(document.getElementById('example2'), {
'sitekey' : 'your_site_key'
});
grecaptcha.render('example3', {
'sitekey' : 'your_site_key',
'callback' : verifyCallback,
'theme' : 'dark'
});
};
</script>
The grecaptcha.getResponse() method accepts an optional "widget_id" parameter, and defaults to the first widget created if unspecified. A widget_id is returned from the grecaptcha.render() method for each widget created, it is not related to the attribute id of the reCAPTCHA container!!
Each reCAPTCHA has its own response data.
You have to give the reCAPTCHA div an ID and pass it to the getResponse method:
e.g.
<div id="reCaptchaLogin"
class="g-recaptcha required-entry"
data-sitekey="<?php echo $this->helper('recaptcha')->getKey(); ?>"
data-theme="<?php echo($this->helper('recaptcha')->getTheme()); ?>"
style="transform:scale(0.82);-webkit-transform:scale(0.82);transform-origin:0 0;-webkit-transform-origin:0 0;">
</div>
<script type="text/javascript">
var CaptchaCallback = function() {
jQuery('.g-recaptcha').each(function(index, el) {
grecaptcha.render(el, {
'sitekey' : jQuery(el).attr('data-sitekey')
,'theme' : jQuery(el).attr('data-theme')
,'size' : jQuery(el).attr('data-size')
,'tabindex' : jQuery(el).attr('data-tabindex')
,'callback' : jQuery(el).attr('data-callback')
,'expired-callback' : jQuery(el).attr('data-expired-callback')
,'error-callback' : jQuery(el).attr('data-error-callback')
});
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
Access response:
var reCaptchaResponse = grecaptcha.getResponse(0);
or
var reCaptchaResponse = grecaptcha.getResponse(1);
I have contact form in footer that always displays and also some pages, like Create Account, can have captcha too, so it's dynamically and I'm using next way with jQuery:
html:
<div class="g-recaptcha" id="g-recaptcha"></div>
<div class="g-recaptcha" id="g-recaptcha-footer"></div>
javascript
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit&hl=en"></script>
<script type="text/javascript">
var CaptchaCallback = function(){
$('.g-recaptcha').each(function(){
grecaptcha.render(this,{'sitekey' : 'your_site_key'});
})
};
</script>
This is a JQuery-free version of the answer provided by raphadko and noun.
1) Create your recaptcha fields normally with this:
<div class="g-recaptcha"></div>
2) Load the script with this:
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
3) Now call this to iterate over the fields and create the recaptchas:
var CaptchaCallback = function() {
var captchas = document.getElementsByClassName("g-recaptcha");
for(var i = 0; i < captchas.length; i++) {
grecaptcha.render(captchas[i], {'sitekey' : 'YOUR_KEY_HERE'});
}
};
Looking at the source code of the page I took the reCaptcha part and changed the code a bit. Here's the code:
HTML:
<div class="tabs">
<ul class="product-tabs">
<li id="product_tabs_new" class="active">Detailed Description</li>
<li id="product_tabs_what">Request Information</li>
<li id="product_tabs_wha">Make Offer</li>
</ul>
</div>
<div class="tab_content">
<li class="wide">
<div id="product_tabs_new_contents">
<?php $_description = $this->getProduct()->getDescription(); ?>
<?php if ($_description): ?>
<div class="std">
<h2><?php echo $this->__('Details') ?></h2>
<?php echo $this->helper('catalog/output')->productAttribute($this->getProduct(), $_description, 'description') ?>
</div>
<?php endif; ?>
</div>
</li>
<li class="wide">
<label for="recaptcha">Captcha</label>
<div id="more_info_recaptcha_box" class="input-box more_info_recaptcha_box"></div>
</li>
<li class="wide">
<label for="recaptcha">Captcha</label>
<div id="make_offer_recaptcha_box" class="input-box make_offer_recaptcha_box"></div>
</li>
</div>
jQuery:
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
var recapExist = false;
// Create our reCaptcha as needed
jQuery('#product_tabs_what').click(function() {
if(recapExist == false) {
Recaptcha.create("<?php echo $publickey; ?>", "more_info_recaptcha_box");
recapExist = "make_offer_recaptcha_box";
} else if(recapExist == 'more_info_recaptcha_box') {
Recaptcha.destroy(); // Don't really need this, but it's the proper way
Recaptcha.create("<?php echo $publickey; ?>", "more_info_recaptcha_box");
recapExist = "make_offer_recaptcha_box";
}
});
jQuery('#product_tabs_wha').click(function() {
if(recapExist == false) {
Recaptcha.create("<?php echo $publickey; ?>", "make_offer_recaptcha_box");
recapExist = "more_info_recaptcha_box";
} else if(recapExist == 'make_offer_recaptcha_box') {
Recaptcha.destroy(); // Don't really need this, but it's the proper way (I think :)
Recaptcha.create("<?php echo $publickey; ?>", "make_offer_recaptcha_box");
recapExist = "more_info_recaptcha_box";
}
});
});
</script>
I am using here simple javascript tab functionality. So, didn't included that code.
When user would click on "Request Information" (#product_tabs_what) then JS will check if recapExist is false or has some value. If it has a value then this will call Recaptcha.destroy(); to destroy the old loaded reCaptcha and will recreate it for this tab. Otherwise this will just create a reCaptcha and will place into the #more_info_recaptcha_box div. Same as for "Make Offer" #product_tabs_wha tab.
var ReCaptchaCallback = function() {
$('.g-recaptcha').each(function(){
var el = $(this);
grecaptcha.render(el.get(0), {'sitekey' : el.data("sitekey")});
});
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallback&render=explicit" async defer></script>
ReCaptcha 1
<div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>
ReCaptcha 2
<div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>
ReCaptcha 3
<div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>
To add a bit to raphadko's answer: since you have multiple captchas (on one page), you can't use the (universal) g-recaptcha-response POST parameter (because it holds only one captcha's response). Instead, you should use grecaptcha.getResponse(opt_widget_id) call for each captcha. Here's my code (provided each captcha is inside its form):
HTML:
<form ... />
<div id="RecaptchaField1"></div>
<div class="field">
<input type="hidden" name="grecaptcha" id="grecaptcha" />
</div>
</form>
and
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
JavaScript:
var CaptchaCallback = function(){
var widgetId;
$('[id^=RecaptchaField]').each(function(index, el) {
widgetId = grecaptcha.render(el.id, {'sitekey' : 'your_site_key'});
$(el).closest("form").submit(function( event ) {
this.grecaptcha.value = "{\"" + index + "\" => \"" + grecaptcha.getResponse(widgetId) + "\"}"
});
});
};
Notice that I apply the event delegation (see refresh DOM after append element ) to all the dynamically modified elements. This binds every individual captha's response to its form submit event.
A good option is to generate a recaptcha input for each form on the fly (I've done it with two but you could probably do three or more forms). I'm using jQuery, jQuery validation, and jQuery form plugin to post the form via AJAX, along with the Recaptcha AJAX API -
https://developers.google.com/recaptcha/docs/display#recaptcha_methods
When the user submits one of the forms:
intercept the submission - I used jQuery Form Plugin's beforeSubmit property
destroy any existing recaptcha inputs on the page - I used jQuery's $.empty() method and Recaptcha.destroy()
call Recaptcha.create() to create a recaptcha field for the specific form
return false.
Then, they can fill out the recaptcha and re-submit the form. If they decide to submit a different form instead, well, your code checks for existing recaptchas so you'll only have one recaptcha on the page at a time.
Here's a solution that builds off many of the excellent answers. This option is jQuery free, and dynamic, not requiring you to specifically target elements by id.
1) Add your reCAPTCHA markup as you normally would:
<div class="g-recaptcha" data-sitekey="YOUR_KEY_HERE"></div>
2) Add the following into the document. It will work in any browser that supports the querySelectorAll API
<script src="https://www.google.com/recaptcha/api.js?onload=renderRecaptchas&render=explicit" async defer></script>
<script>
window.renderRecaptchas = function() {
var recaptchas = document.querySelectorAll('.g-recaptcha');
for (var i = 0; i < recaptchas.length; i++) {
grecaptcha.render(recaptchas[i], {
sitekey: recaptchas[i].getAttribute('data-sitekey')
});
}
}
</script>
It is possible, just overwrite the Recaptcha Ajax callbacks. Working jsfiddle: http://jsfiddle.net/Vanit/Qu6kn/
You don't even need a proxy div because with the overwrites the DOM code won't execute. Call Recaptcha.reload() whenever you want to trigger the callbacks again.
function doSomething(challenge){
$(':input[name=recaptcha_challenge_field]').val(challenge);
$('img.recaptcha').attr('src', '//www.google.com/recaptcha/api/image?c='+challenge);
}
//Called on Recaptcha.reload()
Recaptcha.finish_reload = function(challenge,b,c){
doSomething(challenge);
}
//Called on page load
Recaptcha.challenge_callback = function(){
doSomething(RecaptchaState.challenge)
}
Recaptcha.create("YOUR_PUBLIC_KEY");
Here is a nice guide for doing exactly that:
http://mycodde.blogspot.com.ar/2014/12/multiple-recaptcha-demo-same-page.html
Basically you add some parameters to the api call and manually render each recaptcha:
<script src="https://www.google.com/recaptcha/api.js?onload=myCallBack&render=explicit" async defer></script>
<script>
var recaptcha1;
var recaptcha2;
var myCallBack = function() {
//Render the recaptcha1 on the element with ID "recaptcha1"
recaptcha1 = grecaptcha.render('recaptcha1', {
'sitekey' : '6Lc_0f4SAAAAAF9ZA', //Replace this with your Site key
'theme' : 'light'
});
//Render the recaptcha2 on the element with ID "recaptcha2"
recaptcha2 = grecaptcha.render('recaptcha2', {
'sitekey' : '6Lc_0f4SAAAAAF9ZA', //Replace this with your Site key
'theme' : 'dark'
});
};
</script>
PS: The "grecaptcha.render" method receives an ID
I would use invisible recaptcha. Then on your button use a tag like " formname='yourformname' " to specify which form is to be submitted and hide a submit form input.
The advantage of this is it allows for you to keep the html5 form validation intact, one recaptcha, but multiple button interfaces. Just capture the "captcha" input value for the token key generated by recaptcha.
<script src="https://www.google.com/recaptcha/api.js" async defer ></script>
<div class="g-recaptcha" data-sitekey="yours" data-callback="onSubmit" data-size="invisible"></div>
<script>
var formanme = ''
$('button').on('click', function () { formname = '#'+$(this).attr('formname');
if ( $(formname)[0].checkValidity() == true) { grecaptcha.execute(); }
else { $(formname).find('input[type="submit"]').click() }
});
var onSubmit = function(token) {
$(formname).append("<input type='hidden' name='captcha' value='"+token+"' />");
$(formname).find('input[type="submit"]').click()
};
</script>
I find this FAR simpler and easier to manage.

Resources