How can I post ajax with form validation in bootstrap 5 ?
// Example starter JavaScript for disabling form submissions if there are invalid fields
(function () {
'use strict'
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
I have a big problem with this. Can somebody help me?
The above starter code provided by bootstrap documentation uses the checkValidity() method of JavaScript Constraint Validation API to validate the form.
The HTMLInputElement.checkValidity() method returns a boolean value
which indicates validity of the value of the element. If the value is
invalid, this method also fires the invalid event on the element.
You can make the ajax request if validation is successful as below,
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}else{
//make your ajax request here
}
Here is an example ajax request using JavaScript Fetch API and FormData API
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}else{
try {
const postData = new FormData(form)
const response = await fetch('url', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
});
//Response from server
const data = await response.json();
}catch(e){
//handle error
console.log(e)
}
}
(function () {
'use strict'
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
} else {
event.preventDefault(); // event.default or form submit
formPost(); // call function whatever you want
}
form.classList.add('was-validated')
}, false)
})
})()
function formPost(){
var form_data = $("form#mainform").serialize();
$.ajax({
url: "action.php",
method: "POST",
data: form_data,
// dataType:"json",
success: function (data) {
$('#queryResulDiv').html(data);
console.log(data);
},
error: function (xhr, ajaxOptions, thrownError) {
$('#queryResulDiv').html("ERROR:" + xhr.responseText + " - " + thrownError);
},
complete: function () {
}
})
}
Related
I have a limited understanding of JavaScript, but with some copying and pasting I managed to make a form that gets sent via AJAX.
I'm also running the standard Boostrap 5 input validation. It all worked fine until I found out AJAX fires even without some fields missing.
Then I tried to put the AJAX stuff inside the validation function, but now I need to press "Submit" twice. I understand why, but I don't know how to solve it and would need some help.
This is what I came up with:
(function () {
'use strict'
// Fetch all the forms we want to apply validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
var frm = $('#orderform');
frm.submit(function (e) {
var formData = {
firstName_r: jQuery('#firstName_r').val(),
lastName_r: jQuery('#lastName_r').val(),
action:'the_ajax_mail'
};
$.ajax({
type : 'POST',
url : "<?php echo admin_url('admin-ajax.php'); ?>",
data : formData,
encode : true
}).done(function(data) {
console.log(data);
form.classList.remove('was-validated');
document.getElementById('submitForm').disabled = true;
}).fail(function(data) {
console.log(data);
});
e.preventDefault();
});
}, false)
})
})()
I know the part with var frm = $('#orderform'); and frm.submit(function (e) { needs to go, but I have no idea how...
Try this
(function() {
'use strict'
// Fetch all the forms we want to apply validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function(form) {
form.addEventListener('submit', function(event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
return
}
form.classList.add('was-validated')
var formData = {
firstName_r: jQuery('#firstName_r').val(),
lastName_r: jQuery('#lastName_r').val(),
action: 'the_ajax_mail'
};
$.ajax({
type: 'POST',
url: "<?php echo admin_url('admin-ajax.php'); ?>",
data: formData,
encode: true
}).done(function(data) {
console.log(data);
form.classList.remove('was-validated');
document.getElementById('submitForm').disabled = true;
}).fail(function(data) {
console.log(data);
});
e.preventDefault();
}, false)
})
})()
I have an Asp.Net MVC web application. I want to run some code on the successful response of the API method which is called on form submit.
I have the below Code.
#using (Html.BeginForm("APIMethod", "Configuration", FormMethod.Post, new { #class = "form-horizontal", id = "formID" }))
{
}
$('#formID').submit(function (e) {
$.validator.unobtrusive.parse("form");
e.preventDefault();
if ($(this).valid()) {
FunctionToBeCalled(); //JS function
}
}
But FunctionToBeCalled() function gets called before the APIMethod(), but I want to run the FunctionToBeCalled() function after the response of APIMethod().
So I made the below changes by referring this link. But now the APIMethod is getting called twice.
$('#formID').submit(function (e) {
$.validator.unobtrusive.parse("form");
e.preventDefault();
if ($(this).valid()) {
//Some custom javasctipt valiadations
$.ajax({
url: $('#formID').attr('action'),
type: 'POST',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
}
}
function FunctionToBeCalled(){alert('hello');}
So I am not able to solve the issue.
If you want to execute some work on success, fail, etc. situation of form submission, then you would need to use Ajax call in your view. As you use ASP.NET MVC, you can try the following approach.
View:
$('form').submit(function (event) {
event.preventDefault();
var formdata = $('#demoForm').serialize();
//If you are uploading files, then you need to use "FormData" instead of "serialize()" method.
//var formdata = new FormData($('#demoForm').get(0));
$.ajax({
type: "POST",
url: "/DemoController/Save",
cache: false,
dataType: "json",
data: formdata,
/* If you are uploading files, then processData and contentType must be set to
false in order for FormData to work (otherwise comment out both of them) */
processData: false, //For posting uploaded files
contentType: false, //For posting uploaded files
//
//Callback Functions (for more information http://api.jquery.com/jquery.ajax/)
beforeSend: function () {
//e.g. show "Loading" indicator
},
error: function (response) {
$("#error_message").html(data);
},
success: function (data, textStatus, XMLHttpRequest) {
$('#result').html(data); //e.g. display message in a div
},
complete: function () {
//e.g. hide "Loading" indicator
},
});
});
Controller:
public JsonResult Save(DemoViewModel model)
{
//...code omitted for brevity
return Json(new { success = true, data = model, message = "Data saved successfully."
}
Update: If SubmitButton calls a JavaScript method or uses AJAX call, the validation should be made in this method instead of button click as shown below. Otherwise, the request is still sent to the Controller without validation.
function save(event) {
//Validate the form before sending the request to the Controller
if (!$("#formID").valid()) {
return false;
}
...
}
Update your function as follows.
$('#formID').submit(function (e) {
e.preventDefault();
try{
$.validator.unobtrusive.parse("form");
if ($(this).valid()) {
$.ajax({
url: $('#formID').attr('action'),
type: 'POST',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
}
}
catch(e){
console.log(e);
}
});
Check the browser console for fetching error. The above code will prevent of submitting the form.
I think line $.validator.unobtrusive.parse("form") were throwing error.
For that use you need to add the following jQuery libraries.
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>
I think you should remove razor form tag if you want to post your form using ajax call and add post api URL directly to ajax request instead of getting it from your razor form tag using id:
Here is the revised version of your code :
<form method="post" id="formID">
<!-- Your form fields here -->
<button id="submit">Submit</button>
</form>
Submit your form on button click like:
$('#submit').on('click', function (evt) {
evt.preventDefault();
$.ajax({
url: "/Configuration/APIMethod",
type: 'POST',
dataType : 'json',
data: $('#formID').serialize(),
success: function () {
console.log('form submitted.');
FunctionToBeCalled(); //JS function
}
});
});
function FunctionToBeCalled(){alert('hello');}
You need to use Ajax.BeginForm, this article should help [https://www.c-sharpcorner.com/article/asp-net-mvc-5-ajax-beginform-ajaxoptions-onsuccess-onfailure/ ]
The major thing here is that I didn't use a submit button, I used a link instead and handled the rest in the js file. This way, the form would nver be submitted if the js file is not on the page, and with this js file, it initiates a form submission by itself rather than th form submitting when the submit button is clicked
You can adapt this to your solution as see how it respond. I have somthing like this in production and it works fine.
(function() {
$(function() {
var _$pageSection = $('#ProccessProductId');
var _$formname = _$pageSection.find('form[name=productForm]');
_$formname.find('.buy-product').on('click', function(e) {
e.preventDefault();
if (!_$formname.valid()) {
return;
}
var formData = _$formname.serializeFormToObject();
//set busy animation
$.ajax({
url: 'https://..../', //_$formname.attr('action')
type: 'POST',
data: formData,
success: function(content) {
AnotherProcess(content.Id)
},
error: function(e) {
//notify user of error
}
}).always(function() {
// clear busy animation
});
});
function AnotherProcess(id) {
//Perform your operation
}
}
}
<div class="row" id="ProccessProductId">
#using (Html.BeginForm("APIMethod", "Configuration", FormMethod.Post, new { #class = "form-horizontal", name="productForm" id = "formID" })) {
<li class="buy-product">Save & Proceed</li>
}
</div>
Currently grecaptcha.execute is being executed on page load as in the first JS example below. If reCAPTCHA challenge is triggered this happens when the page has loaded. Ideally this would happen when the form submit button is clicked instead.
So I've tried this by moving this into the submit event (second JS example) and put the axios function into a promise. It's submitting before grecaptcha.execute has finished executing.
What is it that I'm not understanding here?
My first experience with promises so am I not understanding how promises work? Is that not the best solution for this problem? Is is something else entirely?
HTML
<head>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" defer></script>
</head>
JS
const form = document.querySelector('#subscribe');
let recaptchaToken;
const recaptchaExecute = (token) => {
recaptchaToken = token;
};
const onloadCallback = () => {
grecaptcha.render('recaptcha', {
'sitekey': 'abcexamplesitekey',
'callback': recaptchaExecute,
'size': 'invisible',
});
grecaptcha.execute();
};
form.addEventListener('submit', (e) => {
e.preventDefault();
const formResponse = document.querySelector('.js-form__error-message');
axios({
method: 'POST',
url: '/actions/newsletter/verifyRecaptcha',
data: qs.stringify({
recaptcha: recaptchaToken,
[window.csrfTokenName]: window.csrfTokenValue,
}),
config: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
}).then((data) => {
if (data && data.data.success) {
formResponse.innerHTML = '';
form.submit();
} else {
formResponse.innerHTML = 'Form submission failed, please try again';
}
});
}
JS
const onloadCallback = () => {
grecaptcha.render('recaptcha', {
'sitekey': 'abcexamplesitekey',
'callback': recaptchaExecute,
'size': 'invisible',
});
};
form.addEventListener('submit', (e) => {
e.preventDefault();
const formResponse = document.querySelector('.js-form__error-message');
grecaptcha.execute().then(axios({
method: 'POST',
url: '/actions/newsletter/verifyRecaptcha',
data: qs.stringify({
recaptcha: recaptchaToken,
[window.csrfTokenName]: window.csrfTokenValue,
}),
config: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
})).then((data) => {
if (data && data.data.success) {
formResponse.innerHTML = '';
form.submit();
} else {
formResponse.innerHTML = 'Form submission failed, please try again';
}
});
}
I'm using a web service, as I wanted a method that I could use in all pages.
Special attention to the fact you need to return false; and when the ajax request returns, do your post back.
<script type="text/javascript">
function CheckCaptcha()
{
grecaptcha.ready(function () {
grecaptcha.execute('<%#RecaptchaSiteKey%>', { action: 'homepage' }).then(function (token) {
$.ajax({
type: "POST",
url: "../WebServices/Captcha.asmx/CaptchaVerify",
data: JSON.stringify({ 'captchaToken' : token }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
__doPostBack('<%= RegisterButton.UniqueID%>', '');
//console.log('Passed the token successfully');
},
failure: function (response) {
//alert(response.d);
}
});
});
});
return false;
}
</script>
The way I resolved this is by changing the submit button into a dumb button, and handling everything in a js method:
#Html.HiddenFor(model => model.ReCaptchaToken);
<input type="button"
value="Submit"
onclick="onSubmit()"
/>
Then() method waits for the token, puts it in a hidden field, and only then manually submits the form:
<script>
if (typeof grecaptcha == 'object') { //undefined behind the great firewall
grecaptcha.execute('#Config.ReCaptchaSiteKey', { action: 'register' }).then(function (token) {
window.document.getElementById('ReCaptchaToken').value = token;
$('form').submit();
});
} else {
window.document.getElementById('ReCaptchaToken').value = -1;
$('form').submit();
}
</script>
Note: #Html.HiddenFor is MVC - you might not use that.
$('form') is JQuery - you don't necessarily need that - can use getElementById as well.
I have the error MethodNotAllowedHttpException when I submit form data using ajax.
HTML
<form class="form-signin" id="loginForm" role="form" method="POST">
// Form
</form>
<script>
$('#loginForm').submit(function () {
initLogin($('#email').val(),$('#password').val());
});
</script>
JavaScript
function initLogin(email, password) {
$.ajax( {
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
url:'loginModal',
method:'POST',
data: {
strEmail: email,
strPassword: password
},
success: function( bolUpdated ) {
alert('yes');
},
fail: function() {
alert('no');
}
});
}
Route
Route::post( 'loginModal', 'Auth\LoginController#loginModal' );
Controller
public function loginModal( Request $request ) {
Log::info('test');
}
I tried changing the form's type but no luck. Any idea what might be the issue?
You have to stop the form from submitting if you're going t use ajax
$('#loginForm').submit(function (e) {
e.preventDefault(); //<-- here
initLogin($('#email').val(),$('#password').val());
return false; //<---- or here
});
otherwise the form will make a post request to the current page(since action is not there) which has no route for a post request.
prevent default event of form because you have not defined any action for form and its request is being sent to current page
$('#loginForm').submit(function (event) {
event.preventDefault();
initLogin($('#email').val(),$('#password').val());
});
I am submitting a number of forms on my page via php using Ajax. The code works great in forms preloaded with the page. However, I need to submit some dynamic forms that don't load with the page, they are called via other javascript functions.
Please, I need someone to help me review the code for use for forms that don't load with the page. Also the 'failure' condition is not working.
The code is below:
<script type="text/javascript">
feedbar = document.getElementById("feedbar");
jQuery(document).ready(function() {
$('#addressform').on('submit', function (e) {
$.ajax({
type: 'post',
url: 'data/process.php',
data: $('#addressform').serialize(),
success: function () {
feedbar.innerHTML='<div class="text-success">New Addressed Saved Successfully</div>';
},
failure: function () {
feedbar.innerHTML='<div class="text-danger">Error Saving New Address</div>';
}
});
e.preventDefault();
});
});
Thanks.
You need to bind event by existing html (e.g body).
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on()
see api: https://api.jquery.com/on/
Try like this:
$("body").on('submit', '#addressform',function (e) {
$.ajax({
type: 'post',
url: 'data/process.php',
data: $('#addressform').serialize(),
success: function () {
feedbar.innerHTML='<div class="text-success">New Addressed Saved Successfully</div>';
},
failure: function () {
feedbar.innerHTML='<div class="text-danger">Error Saving New Address</div>';
}
});
e.preventDefault();
});
});
you can delegate to document:
$(document).on('submit', '#addressform', function (e) {
$.ajax({
type: 'post',
url: 'data/process.php',
data: $(this).serialize(), // <----serialize with "this"
success: function () {
feedbar.innerHTML='<div class="text-success">New Addressed Saved Successfully</div>';
},
error: function () { //<----use error function instead
feedbar.innerHTML='<div class="text-danger">Error Saving New Address</div>';
}
});
e.preventDefault();
});
});
As you have posted this line as below:
I need to submit some dynamic forms that don't load with the page
What i understand with this line is you want a common submit function for all forms which are generated dynamically, then you can do this:
$(document).on('submit', 'form', function (e) {
$.ajax({
type: 'post',
url: 'data/process.php',
data: $(this).serialize(), // <----"this" is current form context
success: function () {
//some stuff
},
error: function () { //<----use error function instead
//some stuff
}
});
e.preventDefault();
});
});
For your last comment:
You can try to get the text in ajax response like this:
success: function (data) {
feedbar.innerHTML='<div class="text-success">'+ data +'</div>';
},
error: function (xhr) { //<----use error function instead
feedbar.innerHTML='<div class="text-danger">' + xhr.responseText + '</div>';
}
if Success:
here in success function you get the response in data which is the arguement in success function, this holds the response which it requested to the serverside.
if Error:
Same way if something goes wrong at the serverside or any kind of execption has been occured then xhr which is the arguement of error function holds the responseText.
And finally i suggest you that you can place your response in feedbar selector using jQuery this way:
var $feedbar = $('#feedbar');
so in success function:
$feedbar.html('<div class="text-success">'+ data +'</div>');
so in error function:
$feedbar.html('<div class="text-success">'+ xhr.responseText +'</div>');