I am developing a process which involves multiple forms. The idea is that whenever you click the send button of any form, after checking all the inputs have been filled, my js will hide the already completed form in order to show the new one.
The issue is that whenever I click send, the request launches six times inserting the same data over and over. There is no loop involved in the code, so my guess is that this has something to do with this listener:
contactForm.addEventListener('submit', function(event) {
located here:
var validation = Array.prototype.filter.call(contactForm, function(form) {
contactForm.addEventListener('submit', function(event) {
if (contactForm.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
I am not sure however, since I've later tried to make some changes to no avail.
In any case, this is the code I started with:
(function() {
'use strict';
window.addEventListener('load', function() {
var contactForm = document.getElementById('contactForm');
var customerForm = document.getElementById('customerForm');
var validation = Array.prototype.filter.call(contactForm, function(form) {
contactForm.addEventListener('submit', function(event) {
if (contactForm.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
contactForm.classList.add('was-validated');
if (contactForm.checkValidity() === true) {
customerForm.style.display = 'block';
contactForm.style.display = 'none';
event.preventDefault();
(function() {
var contactEmail = document.getElementById('contactEmail').value;
var contactResellerId = 2;
var contactName = document.getElementById('contactName').value;
var contactLastName = document.getElementById('contactLastName').value;
var contactCompany = document.getElementById('contactCompany').value;
var contactRegNum = document.getElementById('contactRegNum').value;
$.ajax({
url: url,
method: 'POST',
crossDomain: true,
withCredentials: true,
data: JSON.stringify({
firstname: contactName,
lastname: contactLastName,
company: contactCompany,
email: contactEmail,
reseller_id: contactResellerId,
comregnum: contactRegNum
}),
dataType: 'json',
contentType: 'application/json',
headers: {
'Authorization': 'Basic '+token,
}
})
.done(function (response) { alert('Se ha creado el contacto!'); })
.fail(function (jqXHR, textStatus, errorThrown) { alert(jqXHR); });
})();
}
}, false);
});
}, false);
})();
And this is what I have right now:
(function() {
'use strict';
window.addEventListener('load', function() {
var contactForm = document.getElementById('contactForm');
var customerForm = document.getElementById('customerForm');
var submitContact = document.getElementById('submitContact');
var validation = Array.prototype.filter.call(contactForm, function(form) {
submitContact.addEventListener('click', function(event) {
if (contactForm.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
contactForm.classList.add('was-validated');
if (contactForm.checkValidity() === true) {
event.preventDefault();
customerForm.style.display = 'block';
contactForm.style.display = 'none';
(function() {
var contactEmail = document.getElementById('contactEmail').value;
var contactResellerId = 2;
var contactName = document.getElementById('contactName').value;
var contactLastName = document.getElementById('contactLastName').value;
var contactCompany = document.getElementById('contactCompany').value;
var contactRegNum = document.getElementById('contactRegNum').value;
$.ajax({
url: url,
method: 'POST',
crossDomain: true,
withCredentials: true,
data: JSON.stringify({
firstname: contactName,
lastname: contactLastName,
company: contactCompany,
email: contactEmail,
reseller_id: contactResellerId,
comregnum: contactRegNum
}),
dataType: 'json',
contentType: 'application/json',
headers: {
'Authorization': 'Basic '+token,
}
})
.done(function (response) { alert('Se ha creado el contacto!'); })
.fail(function (jqXHR, textStatus, errorThrown) { console.log(jqXHR); });
})();
}
}, false);
});
}, false);
})();
This is the form this is getting the info from:
<form class="needs-validation provisioningForm" id="contactForm" novalidate>
<h2 class="title">Crear Contacto</h2>
<div class="form-row">
<div class="col-md-12 mb-3">
<label for="contactName">Nombre</label>
<input type="text" class="form-control" id="contactName" required>
<div class="invalid-feedback">
Debes introducir el nombre del contacto.
</div>
</div>
<div class="col-md-12 mb-3">
<label for="contactLastName">Apellidos</label>
<input type="text" class="form-control" id="contactLastName" required>
<div class="invalid-feedback">
Debes introducir los apellidos del contacto.
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-12 mb-4">
<label for="contactEmail">Email</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupPrepend">#</span>
</div>
<input type="text" class="form-control" id="contactEmail" aria-describedby="inputGroupPrepend" required>
<div class="invalid-feedback">
Debes introducir un correo válido.
</div>
</div>
</div>
<div class="col-md-12 mb-3">
<label for="contactCompany">Empresa</label>
<input type="text" class="form-control" id="contactCompany" required>
<div class="invalid-feedback">
Debes introducir el nombre de la empresa.
</div>
</div>
<div class="col-md-12 mb-3">
<label for="contactRegNum">C.I.F.</label>
<input type="text" class="form-control" id="contactRegNum" required>
<div class="invalid-feedback">
Debes incluir el CIF de la empresa.
</div>
</div>
</div>
<button id="submitContact" class="btn btn-success" type="submit">Enviar</button>
</form>
A few notes:
Everything is working fine. There are no warnings/errors displayed on console. The issue lies in the fact that the POST request is executing 6 times.
There are 5 forms with 5 submit buttons and a total of 5 functions. All have different id's. As I was saying in the beginning, I believe the cause to be the event listener placed on the 'submit'. I think that since the other forms are just hidden, but there, it may be taking the other submits. But after trying to store them in separate variables and to place a .click listener on them and still get the same result I am even more confused.
If you need any extra info I'll post it right away. Thank you all for your time and help.
It looks like you may be adding multiple "submit" events as you surmised. This line appears to be unnecessary:
var validation = Array.prototype.filter.call(contactForm, function(form) {
If you remove it (and the closing }), your submit event should be added only once, on window.load.
Related
I have already made the progress bar and everything. But I have a problem when I choose the file is upload, that's mean the file is uploading twice, once when choosing the file and one once submit the form, and this bad user experience so I want to show the progress bar only when submitting the form, I use Django in backend and ajax recall
my HTML form
<div id="alert-box"></div>
<form id="upload-form" action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
<div id="progress-box" class="d-none">progress</div>
<div class="custom-file">
<input type="file" class="custom-file-input" id="formGroupExampleInput2" required value="{{V_form.video}}">
<label class="custom-file-label" for="formGroupExampleInput2">Choose Video...</label>
</div>
<div class="custom-file mt-5 mb-4">
<input type="file" class="custom-file-input" id="file2" required value="{{V_form.video_poster}}">
<label class="custom-file-label" for="formGroupExampleInput2">Choose Poster For Your Video...</label>
</div>
<div class="d-flex justify-content-center my-3 px-3" > <button class="btn-block btnn-color" id="heel" name="submit_v_form"> Upload</button></div>
</form>
the javascript-Ajax
const file_input_label = document.getElementById('file_input_label')
function input_filename(){
file_input_label.innerHTML = input.files[0].name;
console.log(file_input_label);
}
const uploadForm = document.getElementById('upload-form')
// const input = document.getElementById('formGroupExampleInput2')
const input = document.getElementById('formGroupExampleInput2')
console.log(input)
const alertBox = document.getElementById('alert-box')
const imageBox = document.getElementById('image-box')
const progressBox = document.getElementById('progress-box')
const canceleBox = document.getElementById('cancel-box')
const canceleBtn = document.getElementById('cancel-btn')
const csrf = document.getElementsByName('csrfmiddlewaretoken')
// whenever choose th file something happen
input.addEventListener('change', ()=>{
progressBox.classList.remove('d-none')
canceleBox.classList.remove('d-none')
var filePath = input.value;
var allowedTypes = /(\.mp4|\.mkv|\.avi|\.flv)$/i;
if(!allowedTypes.exec(filePath)){
alertBox.innerHTML = `<div class="alert alert-danger" role="alert">Please Upload the valid file type</div>`
input.value = "";
return false;
}
const img_data = input.files[0]
const url = URL.createObjectURL(img_data)
console.log(img_data)
const fd = new FormData()
fd.append('csrfmiddlewaretoken', csrf[0].value)
fd.append('video', img_data)
$.ajax({
type: 'POST',
url: uploadForm.action,
enctype: 'multipart/form-data',
data: fd,
beforeSend: function() {
console.log('before')
alertBox.innerHTML = ""
// imageBox.innerHTML = ""
},
xhr: function() {
const xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', e=>{
// console.log(e)
if (e.lengthComputable){
const percent = e.loaded / e.total * 100
console.log(percent);
progressBox.innerHTML =
`<div class="progress">
<div class="progress-bar" role="progressbar" style="width: ${percent}%" aria-valuenow=" ${percent}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<p>${percent.toFixed(1)}%</p>`
}
})
canceleBtn.addEventListener('click', ()=>{
xhr.abort()
setTimeout(()=>{
uploadForm.reset()
progressBox.innerHTML = ""
alertBox.innerHTML = ""
canceleBox.classList.add('d-none')
}, 1000)
})
return xhr
},
success: function(response) {
console.log(response)
// imageBox.innerHTML = `<img src="${url}" width="300px">`
// imageBox.innerHTML = `<video class="card" controls src="${url}">`
alertBox.innerHTML = `<div class="alert alert-success" role="alert">Successfully uploaded your video. click upload to upload your video</div>`
},
error: function(error){
console.log(error)
alertBox.innerHTML = `<div class="alert alert-danger" role="alert">Ups something went wrong!</div>`
},
cache: false,
contentType: false,
processData: false,
})
})
I think what you are trying to achieve here is to show the progress bar only on Ajax submit. So you can just add/remove the display-none class on each operational methods as below.
input.addEventListener('change', () => {
progressBox.classList.add('d-none') // Though this class is already added in html [seems redundant here].
$.ajax({
type: 'POST',
beforeSend: function() {
progressBox.classList.remove('d-none')
},
success: function(response) {
progressBox.classList.add('d-none')
},
error: function(error) {
progressBox.classList.add('d-none')
})
}
Hope this will be one way to work around but let me know if this solves your problem.
The following code is working fine when the form is submitted correctly with all valid data in the first attempt. If there is any server side error after submitting the form then when user resubmits the form the recaptcha does not reset.
Following is the sample code:
html-form
<script src="https://www.google.com/recaptcha/api.js"></script>
<div>
<form name="signupForm" method="POST" action="/signup">
<div class="form-group mobile-number">
<input type="tel" id="mobileNo" class="form-control" name="mobileNumber" maxlength="10"
autofocus>
<label for="mobile"> Your Mobile no. </label>
</div>
<div class="g-recaptcha"
data-sitekey="{key}"
data-callback="setResponse"
data-badge="inline"
data-size="invisible">
</div>
<input type="hidden" id="captcha-response" name="captcha-response"/>
<button id="submitButon" type="submit">Sign me up!</button>
</form>
</div>
javascript
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
function setResponse(response) {
document.getElementById('captcha-response').value = response;
submitForm();
}
function submitForm() {
var $form = $("form");
var data = JSON.stringify($form.serializeObject());
var myJsonObject = JSON.parse(data);
data = JSON.stringify(myJsonObject);
$.ajax({
type: "POST",
url: "dummy url",
contentType: "application/json",
xhrFields: {withCredentials: true},
data: data,
success: function (data, textStatus, request) {
// success
},
error: function (xhr, err) {
// logics here
grecaptcha.execute();
setResponse;
}
});
}
</script>
<script>
jQuery(document).ready(function () {
//homepage form
$('form[name="signupForm"]').validate({
onfocusout: function (element) {
$(element).valid();
},
rules: {
mobileNumber: {
required: true,
minlength: 10,
maxlength: 10
}
},
// Specify validation error messages
messages: {
mobileNumber: "A valid mobile number is of 10-digit",
},
//submit handler
submitHandler: function (form) {
submitForm();
}
});
});
</script>
I think the error is in ajax call but not able to figure out why the captcha is not resetting again.
I'm using laravel framework and JQuery and AJAX in order to save a new entry into my database, however I fail at capturing the values of my inputs since validation is failing (some fields are required and I can't seem to gather data correctly so they are empty).
This is the error:
errors: {…}
body: Array [ "The body field is required." ]
image: Array [ "The image field is required." ]
title: Array [ "The title field is required." ]
<prototype>: Object { … }
message: "The given data was invalid."
Here is my jQuery code:
$('.form_new_button').click(function() {
var linked_entry = $(this).attr("data-link");
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name=csrf-token]').attr('content')
}
});
switch (linked_entry) {
case "sliders":
console.log('new slider button clicked');
var form = $('new_slider_form').get(0);
$.ajax({
async: true,
url: '/sliders',
type: 'POST',
data: new FormData(form),
dataType: 'JSON',
processData: false,
contentType: false,
success: function(data) {
$('.form_valid_container').html('<span class="form_valid_text">✓ ' + data.success + '</span>');
form.trigger("reset");
console.log(data.success, data.errors);
},
error: function(data) {
var errors = data.responseJSON;
console.log(errors);
$.each(errors, function() {
$('.form_error_container').html('<span class="form_error_text">✘ ' + errors.message + '</span>')
});
}
});
break;
default:
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
And this is the form modal I'm using to fill the input fields with data:
<div class="modal_overlay_maincontainer closeable form_new_modal" data-link="sliders">
<form id="new_slider_form" class="modal_container" method="POST">
<i class="close fa fa-times-circle" title="Cerrar"></i>
<h2 class="modal_title">Nueva Diapositiva</h2>
<div class="modal_body_container">
<div class="modal_body_check_container">
<span class="modal_body_options_title">Visible</span>
<input class="modal_body_check" name="isVisible" type="checkbox" title="La diapositiva se subirá al pasador de diapositivas" required>
</div>
<div class="modal_body_check_container">
<span class="modal_body_options_title">Imagen</span>
<input type="file" name="image" required>
</div>
<input class="modal_input" type="text" name="title" placeholder="Titulo de la diapositiva" required>
<textarea class="modal_input_textarea" name="body" placeholder="Contenido de la diapositiva" required></textarea>
</div>
<div class="modal_footer_container">
<button class="modal_footer_add_button form_new_button" type="button" data-link="sliders" title="Crear nueva entrada">Crear</button>
<button class="modal_footer_reset_button form_reset_button" type="button" title="Resetear los campos">Reset</button>
</div>
</form>
</div>
Try
var form = $('new_slider_form').get(0);
$.ajax({
type: "POST",
async: true,
url: '/sliders',
data: $(form).serialize(),
success: function(data) {
$('.form_valid_container').html('<span class="form_valid_text">✓ ' + data.success + '</span>');
form.trigger("reset");
console.log(data.success, data.errors);
},
error: function(data) {
var errors = data.responseJSON;
console.log(errors);
$.each(errors, function() {
$('.form_error_container').html('<span class="form_error_text">✘ ' + errors.message + '</span>')
});
}
});
I am trying to implement the newest ReCaptcha (aka "invisible" ReCaptcha) within an form using jQuery and an "ajax" request.
ReCaptcha documentation: https://developers.google.com/recaptcha/docs/invisible
My form:
<form id="myForm" >
<input type="email" name="email" /><br />
<input type="password" name="password" /><br/>
<!--<input type="submit" value="log in" />-->
<button class="g-recaptcha" data-sitekey="6LdK..." data-callback="onSubmit">log in</button>
</form>
<div id="status"></div>
My javascript (jQuery):
<script>
function onSubmit(token){
document.getElementById("myForm").submit();
}
$(document).ready(function(){
$("#myForm").submit(function(event){
event.preventDefault();
var datas = $("#myForm").serialize();
$.ajax({
type: "POST",
url: "test.php",
data: datas,
dataType: "json",
beforeSend: function(){
$("#status").html("logging in...");
},
success: function(response){
$("#status").html(response.text);
if(response.type=="success"){
window.location.replace("/myaccount");
}
},
error: function(){
$("#status").html("Failed.");
}
});
});
});
</script>
ReCaptcha requires to set a "data-callback", which I am not sure how to bind with my already existing ".submit(function(event)" function.
My "onSubmit()" trick did not work, it ignores the "ajax" and refreshes the page.
How do I send the "g-recaptcha-response" value within my "datas" variable to POST it to test.php?
So here is how I solved it after digging further in Invisible reCAPTCHA's doc, and learning a bit of jQuery obviously since I was not very familiar with JS (cool stuff):
My head tag with the javascript (and a bit of css to remove the ugly Google badge):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=fr" async defer></script>
<style>
.grecaptcha-badge{
display:none;
}
</style>
<script>
var onloadCallback = function(){
grecaptcha.render("emplacementRecaptcha",{
"sitekey": "YOUR_RECAPTCHA_SITEKEY_HERE",
"badge": "inline",
"type": "image",
"size": "invisible",
"callback": onSubmit
});
};
var onSubmit = function(token){
var userEmail = $("#userEmail").val();
var userPassword = $("#userPassword").val();
var userTfaOtp = $("#userTfaOtp").val();
$.ajax({
type: "POST",
url: location.href,
data:{
userEmail: userEmail,
userPassword: userPassword,
userTfaOtp: userTfaOtp,
userJetonRecaptcha: token
},
dataType: "json",
beforeSend: function(){
$("#statutConnexion").html("Traitement de votre requête d'authentification en cours...");
},
success: function(response){
$("#statutConnexion").html(response.Message);
if(response.Victoire){
$("#formulaireConnexion").slideUp();
window.location.replace("/compte");
}
else{
grecaptcha.reset();
}
},
error: function(){
$("#statutConnexion").html("La communication avec le système d'authentification n'a pas pu être établie. Veuillez réessayer.");
grecaptcha.reset();
}
});
};
function validate(event){
event.preventDefault();
$("#statutConnexion").html("Validation de votre épreuve CAPTCHA en cours...");
grecaptcha.execute();
}
function onload(){
var element = document.getElementById("boutonConnexion");
element.onclick = validate;
}
</script>
HTML:
<div id="formulaireConnexion">
<input type="email" name="userEmail" id="userEmail" placeholder="Courriel" title="Courriel" required="required" /><br />
<input type="password" name="userPassword" id="userPassword" placeholder="Mot de passe" title="Mot de passe" required="required" /><br/>
<input type="text" name="userTfaOtp" id="userTfaOtp" placeholder="Double authentification (optionnelle)" autocomplete="off" pattern="[0-9]{6}" title="Six caractères numériques" maxlength="6" /><br />
<div id="emplacementRecaptcha"></div>
<button id="boutonConnexion">Connexion</button>
</div>
<div id="statutConnexion"></div>
<script>onload();</script>
Let me know if you need the whole PHP as well since it's out of the scope of this question. You will probably need to change "url: location.href," within the JS above since in my case the script rendering the HTML form and the JS and dealing with the POST vars is the same (not great, testing purpose). Basically I just verify the POST vars then finally return a json like:
$jsonVictoire = true; // boolean
$jsonMessage = 'anything you want to tell your visitor'; // string
$return =
json_encode(
array(
'Victoire'=>$jsonVictoire,
'Message'=>$jsonMessage
)
);
die($return);
<script defer>
function onSubmit(token) {
var f = $("#myForm");
$.ajax({
type: "POST",
url: "test.php",
data: f.serialize(),
dataType: "json",
beforeSend: function(){
$("#status").html("logging in...");
},
success: function(response){
$("#status").html(response.text);
if(response.type=="success"){
window.location.replace("/myaccount");
} else {
$("#status").html("Captcha failed.");
}
},
error: function(){
$("#status").html("Failed.");
}
});
}
</script>
In test.php you need to verify captcha on server side:
<?php
if(isset($_POST['g-recaptcha-response'])) {
$result = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=[YOUR_SECRET_KEY]&response=$_POST["g-recaptcha-response"]&remoteip=$_SERVER["REMOTE_ADDR"]'), TRUE);
if($result['success'] == 1) {
// Captcha ok
} else {
// Captcha failed
}
}
?>
<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onScriptLoad" async defer></script>
<div id="login_page" class="g-recaptcha" data-size="invisible" data-sitekey="your sitekey" data-callback="login_page"></div>
<script>
window.onScriptLoad = function () {
// this callback will be called by recaptcah/api.js once its loaded. If we used
// render=explicit as param in script src, then we can explicitly render reCaptcha at this point
// element to "render" invisible captcha in
var htmlEl = document.querySelector('.g-recaptcha');
// option to captcha
var captchaOptions = {
sitekey: 'your site key...',
size: 'invisible',
// reference to an actual function
callback: window.onUserVerified
};
// Only for "invisible" type. if true, will read value from html-element's data-* attribute if its not passed via captchaOptions
var inheritFromDataAttr = true;
// now render
recaptchaId = window.grecaptcha.render(htmlEl, captchaOptions, inheritFromDataAttr);
};
window.onUserVerified = function (token){
Your ajax code....
}
$("#blog_inquiry").click(function(e){
//var gg = grecaptcha.getresponse();
var token = window.grecaptcha.getResponse(recaptchaId);
// if no token, mean user is not validated yet
if (!token) {
window.grecaptcha.execute(recaptchaId);
return;
}
});
</script>`
<form method="POST" class="userform" id="loginForm">
<div data-role="content">
<h2> Login:</h2>
<div data-role="fieldcontain">
<input name="email" placeholder="put your name" type="email" data-mini="true">
</div>
<div data-role="fieldcontain">
<input name="password" placeholder="enter your password" type="password" data-mini="true">
</div>
<input type="submit" data-theme="a" value="submit" id="submitButton">
<h5 align="center">
Forget password?
</h5>
</div>
</form>
this is my login.js
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
var $bro = $('#loginForm');
$('#submitButton').click(function(e) {
//console.log("submit button has been clicked");
e.preventDefault(); //cancel form submit
var jsObj = $bro.serializeObject()
, ajaxObj = {};
//console.log(jsObj);
ajaxObj = {
type: "POST",
url: "http://192.168.0.100:8080/AdvancedLibrarySystem/api/v1/login",
data: JSON.stringify(jsObj),
contentType:"application/json",
error: function(jqXHR, textStatus, errorThrown) {
console.log("Error " + jqXHR.getAllResponseHeaders() + " " + errorThrown);
},
success: function(data) {
console.log(data);
if(data[0].status == '200') {
alert("Welcome!!!")
$('#div_ajaxResponse').text( data[0] );
$.mobile.changePage('home.html');
}
else{
alert("Incorret Username or Password!!!")
}
},
complete: function(XMLHttpRequest) {
//console.log( XMLHttpRequest.getAllResponseHeaders() );
},
dataType: "json" //request JSON
};
$.ajax(ajaxObj);
});
I'm trying to use an authentification in phonegap via ajax but if i'm trying to run that code in chrome console it works fine but when i'm using it in my phonegap application it's not giving response in the server... Anyone can help me out please...
I am not sure what you mean by 'not giving response in the server', but one thing worth checking out is the cross-domain options in the config.xml of your phonegap project. There should be an "access" tag in there that specifies what domains can be accessed. Try setting it to "*" and try again.