I have two forms in modal windows on one page (authorization and registration). For both forms, I connect an invisible recaptcha (v2). Here is code of recaptcha init:
var idCaptcha1, idCaptcha2;
var onloadReCaptchaInvisible = function () {
//login
idCaptcha1 = grecaptcha.render('recaptcha1', {
"sitekey": "6LfpltgUAAAAAMW3PstNGrEk3pMos0TzN9jyL7mT",
"callback": "onSubmitReCaptcha1",
"size": "invisible"
});
//reg
idCaptcha2 = grecaptcha.render('recaptcha2', {
"sitekey": "6LfpltgUAAAAAMW3PstNGrEk3pMos0TzN9jyL7mT",
"callback": "onSubmitReCaptcha2",
"size": "invisible"
});
};
function onSubmitReCaptcha1(token) {
alert('test');
sendForm('signin', idCaptcha1);
}
function onSubmitReCaptcha2(token) {
sendForm('signup', idCaptcha2);
}
When user submit any form, I try to find out whats form exctly, and execute captcha I need:
$('form').submit(function(event) {
// отменим отправку форму на сервер
event.preventDefault();
switch($(this).closest('.modal').attr('id')){
case 'signin':
grecaptcha.execute(idCaptcha1);
case 'signup':
grecaptcha.execute(idCaptcha2);
}
});
Finally, this is the code of sending form function:
function sendForm(id,captcha){
alert(id);
let form = $('#'+id).find('form'),
url = form.attr('action'),
formData = new FormData(form);
formData.append('g-recaptcha-response', grecaptcha.getResponse(captcha));
console.log(url);
console.log(formData);
}
So, captchas work fine, besides fact both of them appear at once. What I did wrong?
I suspect problem in $('form').submit() but I cant find out reason.
You forgot the break statement at the end of each case. If you match the first case and don't have break, it falls through and executes the next case, so both recaptchas are shown.
$('form').submit(function(event) {
// отменим отправку форму на сервер
event.preventDefault();
switch($(this).closest('.modal').attr('id')){
case 'signin':
grecaptcha.execute(idCaptcha1);
break;
case 'signup':
grecaptcha.execute(idCaptcha2);
break;
}
});
Related
Really stuck on this one, I've inherited a website that was built using a page builder vomits
I've created a script that guards the downloads on this page (resources) the user must fill out a form and input their details, the form submission works correctly and when it completes I open the resource using window.open(href, '_blank') this works correctly on the first submit but if you try and download a second resource it always returns the first clicked href and opens that.
Here is my code: Im getting all the anchors on the page, looping over them and adding an onClick event listener, when a user clicks the link it opens the modal, then jquery to submit the form. As you can see in the comments the href is logged correctly when outside of the submit function, however when inside the submit function it always reverts back to the first href clicked.
e.g user clicks resource1, submits the form and downloads, user then clicks resource2, submits the form but is directed to resource1 :'(
jQuery(document).ready(function ($) {
const anchors = Array.from(
document.querySelectorAll('.page-id-17757 .elementor-element-7121f28 .elementor-widget-icon-list a')
);
const modal = document.querySelector('#resources-modal');
function getFormData($form) {
var unindexed_array = $form.serializeArray();
var indexed_array = {
data: {},
};
$.map(unindexed_array, function (n, i) {
indexed_array.data[n['name']] = n['value'];
});
return indexed_array;
}
function updateFormResponse(status, anchor) {
if (status == 200) {
$('.form-response').html('Success.');
modal.close();
$('.form-response').html('');
$('#resources-submit').prop('disabled', false);
} else {
$('.form-response').html('There has been an error, please refresh the page and try again');
$$('#resources-submit').prop('disabled', false);
}
}
anchors.forEach((anchor) => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
modal.showModal();
let href = e.target.parentElement.href;
$('.resources-download').submit(function (e) {
console.log(e);
e.preventDefault();
e.stopImmediatePropagation();
let form = $(this);
$('#resources-submit').prop('disabled', true);
let formData = getFormData(form);
$.ajax({
url: '/wp-content/themes/hello-elementor/raisley/resources-download.php',
type: 'POST',
data: formData,
dataType: 'json',
complete: function (data) {
updateFormResponse(data.status, href);
if (data.status == 200) downloadResource();
},
});
});
console.log(href); // this logs the correct href
function downloadResource() {
console.log(href); // logs incorrect href, always returns the first clicked href
window.open(href, '_blank');
}
});
});
});
I'm really struggling with this one, need some pro help please!
Thanks,
I'm trying to put recaptcha v3 on a form but inserting the token into a hidden input field doesn't work - on the first submission.
Here is the code that I doctored a little. I added an alert and stopped the sumbit to see what's happening. This code is in a separate bundle.js file.
var form = document.querySelector('#contact-form');
var inputs = form.querySelectorAll('input');
$(form).submit(function(e) {
e.preventDefault();
grecaptcha.ready(function() {
grecaptcha.execute('secret_key', {
action: 'my_action'
}).then(function(token) {
document.getElementById('tokenField').value = token;
alert('token is; ' + token); // inserted for troubleshooting
});
});
removeMessageBox();
validation();
var alerts = document.querySelectorAll('.alert-text');
if (alerts.length == 0) {
// document.forms['contact-form'].submit();
}
});
With this code as written, the alert shows a valid token but tokenField has no value. tokenField gets the token AFTER you press OK on the alert. What is the problem??? I have tried everything.
If you take out the alert and uncomment submit, tokenField is empty on submission.
Note that this script also calls validation() and removeMessageBox(), which removes validation error messages.
If validation() stops the submission for some reason, you can fix the problem, submit again and tokenField gets it value and everything works great - the second time.
As far as I can tell, the field is being set inside of a callback, while the other functions are running in the main function. You can either put all of the code into the callback function for the .then function, or use an async function.
Callback
$(form).submit(function(e) {
e.preventDefault();
grecaptcha.ready(function() {
grecaptcha.execute('secret_key', {
action: 'my_action'
}).then(function(token) {
document.getElementById('tokenField').value = token;
removeMessageBox();
validation();
var alerts = document.querySelectorAll('.alert-text');
if (alerts.length == 0) {
// document.forms['contact-form'].submit();
}
});
});
});
Async
$(form).submit(function(e) {
e.preventDefault();
grecaptcha.ready(async function() {
const token = await grecaptcha.execute('secret_key', {
action: 'my_action'
});
document.getElementById('tokenField').value = token;
removeMessageBox();
validation();
var alerts = document.querySelectorAll('.alert-text');
if (alerts.length == 0) {
// document.forms['contact-form'].submit();
}
});
});
Beforeinstallprompt triggers on every load.
I have used the code here: https://developers.google.com/web/fundamentals/app-install-banners/
I am not using the The mini-info bar which i have dissabled by calling e.preventDefault();
The problem is that the showAddToHomeScreen(); is called on every load if the user does not click addToHomeScreen.
I want the showAddToHomeScreen(); function to be called only every month or so by storing information about the last "canceled" click in sessions or something similar. Isn't google suppose to do this on it's own?
This i found on the following link:
https://developers.google.com/web/updates/2018/06/a2hs-updates
You can only call prompt() on the deferred event once, if the user clicks cancel on the dialog, you'll need to wait until the beforeinstallprompt event is fired on the next page navigation. Unlike traditional permission requests, clicking cancel will not block future calls to prompt() because it call must be called within a user gesture.
window.addEventListener('beforeinstallprompt', function (e) {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
showAddToHomeScreen();
});
function showAddToHomeScreen() {
var prompt = document.querySelector(".a2hs-prompt");
prompt.style.display = "flex";
var open = document.querySelector(".a2hsBtn");
open.addEventListener("click", addToHomeScreen);
var close = document.querySelector(".a2hsBtn-close");
close.addEventListener("click", function() {
prompt.style.display = "none";
});
}
function addToHomeScreen() {
var prompt = document.querySelector(".a2hs-prompt");
// hide our user interface that shows our A2HS button
prompt.style.display = 'none';
if (deferredPrompt) {
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then(
function (choiceResult) {
if (choiceResult.outcome === 'accepted') {
show_ad2hs_success_message();
}
deferredPrompt = null;
});
}
}
You have to define your own session and add expire date. This is simple with ajax. This is how i did:
Javascript:
$(document).ready(function() {
$.ajax({
url: '/update_session_addtohomescreen',
success: function (session_expired) {
if(session_expired=='True'){
showAddToHomeScreen();
}
},
error: function () {
alert("it didn't work");
}
});
});
This is wrapping the showAddToHomeScreen(); function
View
#csrf_exempt
def update_session_addtohomescreen(request):
if request.is_ajax():
number_of_days_till_expire = 1
now_in_secs = time.time()
if not 'last_session_coockie' in request.session or now_in_secs > request.session['last_session_coockie']+60:#number_of_days_till_expire*86400:
session_expired = True
request.session['last_session_coockie'] = now_in_secs
else:
session_expired = False
return HttpResponse(session_expired)
return None
You should though include csrf token in your request and also add the url to urls.py
I'm typing this question away from my computer so I don't have the exact code, but the question might be straightforward enough without it.
When I have a submit button directly within an Ajax form and I click the button directly to submit, everything works fine, and as expected. The Ajax.Form POSTs back to the controller which returns a partial view that is rendered inside the current View that I have.
But what I need is for a button to be clicked in the Ajax.Form, and for a JavaScript function to run. The JavaScript function will do some vaildation which decides whether to submit the Ajax.Form or not.
I have tried putting 2 buttons in the Ajax.Form, a hidden submit button and a regular button. I used the onclick event of the regular button to call my JavaScript function which then called the click method of the hidden submit button. (I have also tried just submitting the Ajax.Form directly with document.forms[formname].submit() )
This sort of works.. But not correctly for some reason. The Ajax.Form POSTs back to the controller but when a partial view is returned from the controller, the partial view is the only thing rendered, and it is rendered as basic html with no css/bootstrap.
What is the difference between actually clicking the submit button and doing so programmatically?
How can Achieve what I am trying to do?
Edit
#using (Ajax.BeginForm("GetInstructorInfo", "Incident", FormMethod.Post, new AjaxOptions { OnBegin = "lookupInstructor();", UpdateTargetId = "InstructorInfo" }, new { #class = "form-inline", role = "form", #id = "instructorInfoForm", #name = "instructorInfoForm" }))
{
//code in here
}
Edit 2 / 3:
<script>
function lookupInstructor()
{
if ($('input[name="Instructors['+userInputInstructor+'].Username'+'"]').length > 0) //Don't allow user to enter multiple instances of the same Instructor
{
document.getElementById("InstructorUsername").value = ''; //clear textbox value
return false;
}
var userInputInstructor = document.getElementById("InstructorUsername").value;
$.ajax({
url: '#Url.Content("~/Incident/LookUpUsername")',
data: { userInput: userInputInstructor },
success: function (result) {
if (result.indexOf("not found") != -1){ //if not found
$("#InstructorNotFoundDisplay").show();
document.getElementById("InstructorUsername").value = ''; //clear textbox value
$('#InstructorInfo').empty();
return false;
}
else {
$("#InstructorNotFoundDisplay").hide();
return true;
}
}
});
}
</script>
You can use the OnBegin() ajax option to call a function that runs before the form is submitted (and return false if you want to cancel the submit). For example
function Validate() {
var isValid = // some logic
if (isValid) {
return true;
} else {
return false;
}
}
and then in the Ajax.BeginForm() options
OnBegin = "return Validate();"
Edit
Based on the edits to the question and the comments, you wanting to call an ajax function in the OnBegin() option which wont work because ajax is asynchronous. Instead, use jQuery.ajax() to submit you form rather than the Ajax.BeginForm() method (and save yourself the extra overhead of including jquery.unobtrusive-ajax.js).
Change Ajax.BeginForm() to Html.BeginForm() and inside the form tags replace the submit button with <button type="button" id="save">Save</button>and handle its .click() event
var form = $('#instructorInfoForm');
var url = '#Url.Action("GetInstructorInfo", "Incident")';
var target = $('#InstructorInfo');
$('#save').click(function() {
if ($('input[name="Instructors['+userInputInstructor+'].Username'+'"]').length > 0) {
....
return; // exit the function
}
$.ajax({
....
success: function (result) {
if (result.indexOf("not found") != -1) {
....
}
else {
$("#InstructorNotFoundDisplay").hide();
// submit the form and update the DOM
$.post(url, form.serialize(), function(data) {
target.html(data);
});
}
}
});
});
I've looked around and none of the other similar posts have helped me. I have built an AJAx based form in Yii 2 and jQuery and it seems it submits the form twice.
My form:
$form = ActiveForm::begin([
'id' => 'company_form',
'ajaxDataType' => 'json',
'ajaxParam' => 'ajax',
'enableClientValidation' => false
]);
My JS code:
$(document).ready(function() {
/* Processes the company signup request */
$('#company_form').submit(function() {
signup('company');
return false;
});
})
function signup(type) {
var url;
// Set file to get results from..
switch (type) {
case 'company':
url = '/site/company-signup';
break;
case 'client':
url = '/site/client-signup';
break;
}
// Set parameters
var dataObject = $('#company_form').serialize();
// Run request
getAjaxData(url, dataObject, 'POST', 'json')
.done(function(response) {
//.........
})
.fail(function() {
//.....
});
// End
}
Shouldn't the standard submit be stopped by me putting the return: false; in the javascript code?
Why is it submitting twice?
More Info: However the strange thing is, that only appears to happen the first time; if I hit submit again it only submits once; but if I reload the page and hit submit it will do it twice again.
You may need to change your code like below:
$('#company_form').submit(function(e) {
e.preventDefault();
e.stopImmediatePropagation();
signup('company');
return false;
});
http://api.jquery.com/event.stoppropagation/
http://api.jquery.com/event.stopimmediatepropagation/
Solution common
Next JS will works with any state of 'enableClientValidation':
$('#company_form').on('beforeSubmit', function (e) {
signup('company');
return false;
});
https://yii2-cookbook.readthedocs.io/forms-activeform-js/#using-events