I am working on a dynamic online form website. In the main form, I have multiple sub-forms which can be added and deleted dynamically.
<div class='subform'>
//form fields
<input ...>
...
<button class='subform_submit'>
</div>
For each subform, I bind an AJAX call on the subform's submit button like this:
$('#main').on('click', '.subform_submit', function(){
// Get this subform's user input
...
$.ajax({
url: ..,
type: ..,
data: /* this subform's data */
});
});
So in that page, I may have 0 to 10 subforms depending on the user's selection.
I also have a main submit button on the bottom of the page, which can submit those subforms and the main form's data together.
$('#main').on('click', '#submit', function(e){
$('.subform_submit').click(); // Submit each subform
bootbox.confirm({ });
})
Once main submit button is clicked, I want to show a loading picture and then show a dialog box (I use bootbox.confirm() here) until all AJAX calls have completed.
This dialog box is telling user that whole form including sub-forms has been submitted.
But the problem is that each AJAX call may take 2 seconds to complete and I don't know how may calls may be pending completion. How can I write this main submit button so that it will:
Show the loading image immediately, and
Hide the loading image and show the dialog box after all AJAX calls have completed?
Keep track of how many sub-forms there are;
$subFormsCount = $('.subform').length;
Keep track of how many forms have been submitted;
$submittedForms = 0;
Each time a form finishes submitting, add to the $submittedForms;
$.ajax({
..
..
done: function(){
$submittedForms++;
}
})
Create a global timer to see if the number of submitted forms matches the total number of subforms. If true, hide the dialog box;
setInterval(function(){
if($submittedForms == $subFormsCount){
$('.dialog').show();
}
}, 50ms)
Edit
You could skip the global timer (as this will probably be a few milliseconds out) - include the check in your ajax.done instead;
$.ajax({
..
..
done: function(){
$submittedForms++;
if($submittedForms == $subFormsCount){
$('.dialog').show();
}
}
})
You want to use .done() in order to specify code that should wait until the AJAX asynchronous function completes.
$.ajax({
url:..,
type: ..,
data: /* this subform's data*/ })
.done(function() {
//Put code here
});
Have you tried .ajaxStop() event handler ?
$(document).ajaxStop(function() {
// place code to be executed on completion of last outstanding ajax call here
});
also, check this answer
I assume you have 9 subform and 1 main form.
Code for 8 subform will be same.
I use here async:false : Means next ajax will not be call until 1st one is not completed.
Sample Code Format :
var id = 5;
$.ajax({
url: ,
type: 'POST',
data: {'id':id},
dataType: 'JSON',
async: false,
error : function(xhr, textStatus, errorThrown) {
alert('An error occurred!');
},
success : function(response){
}
});
Just set variable in your last sub form that is 9th subform.
success : function(response){
var counter = true;
}
if(counter){
/* Code to show dialog.*/
}
You can use $.when to wait for each request to complete. Something like this should get you close. You'd basically want to store all the ajax requests in an array and pass that to when as the arguments.
$('#main').on('click', '.subform_submit', function () {
var formRequests = $('.subform').map(function () {
var $form = $(this);
return $.ajax({
url: '',
data: $form.serialzeArray()
});
}).get();
$.when.apply(undefined, formRequests).done(function () {
console.log('All done!');
});
});
Here goes a very similar little demo I just made up: https://jsfiddle.net/g9a06y4t/
Related
I am building a web app, I am submitting a form with jquery, if I should click on the submit button the first time, it will sub!it once, if I should click it the second time after the first form is submitted, it will submit twice, if I could click it the third time, it will submit 3 times and so on, pls how will I prevent it. Am not talking of disabling the submit button, and I also if I should reload the page if it reset the submission
$.ajax({ type: "POST", url: url, data: data, success: success, dataType: dataType });
This is a classic example. Basically, what you want to do, in your submit method, you want to disable the submit button before you call your ajax. Once the ajax is completed, you will have 2 outcomes, success, or error. In both cases, you want to enable your submit button.
function buttonSubmit() {
let buttonSelector = event.srcElement;
buttonSelector.disabled = true;
$.post({
url: "your-api",
data: {
someData: "kjfgkdjfglkdf"
},
success: function (result) {
// handle your success, do stuff
buttonSelector.disabled = false;
},
error: function (response) {
// handle your error, do stuff
buttonSelector.disabled = false;
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" onclick="buttonSubmit()">Click Me!</button>
I have some JS files included in my page that are simple for displaying blocks on click ant etc..
On another part of page, I have a button. When I click it an ajax call is made that returns some values that I display on the page. To display it, I'm reloading part of page like this:
$(document).ready(function () {
$(document).on('click', '.add', function (e) {
$this = $(this);
$.ajax({
type: 'POST',
url: 'add',
dataType: 'JSON',
data: {product: $this.parent('.input-append').find('input').data('id'),quantity: $this.parent('.input-append').find('input').val()},
success: function (data) {
if(data.success == false){
alert('error')
}else{
$('.test').load(" .test");
$('.sidebar').load(" .sidebar");
$('.top').load(" .top");
}
}
});
});
This reloads part of page, displays values and etc..
However, after the ajax call is made, the JS stops working. When I click my buttons, nothing happens. No errors or anything.
I think it has to do with the ajax when I refresh part of twig and it messes up the previously loaded JS files. But what can I do in that situation? Somehow refresh the loaded JS files? How?
You have to attach event listener on button starting from the container which doesn't get reloaded by Ajax request, like this:
//#mainCont is a container that doesn't get reloaded by Ajax
$("#mainCont").on("click", ".yourBtn", function(){
//do something
});
As said #Nacho M, you need to reinit listener from the loaded element, so you hsould have something like this :
function init() {
$(document).on('click', '.yourclass', function (e) {
//your content
}
// add every button who needs to be reloaded.
}
Init them on loading page first :
$("document").ready(function() {
init();
})
And on success of Ajax call :
$.ajax({
type: 'POST',
url: 'add',
dataType: 'JSON',
data: {product: $this.parent('.input-append').find('input').data('id'),quantity: $this.parent('.input-append').find('input').val()},
success: function (data) {
if(data.success == false){
alert('error')
}else{
$('.test').load(" .test");
$('.sidebar').load(" .sidebar");
$('.top').load(" .top");
init();
}
}
});
I have a loading.gif that launches each time the user makes an AJAX powered search. However, I've got some search fields that automatically show suggestions while the user types, also powered by AJAX.
Now my loading.gif appears on the user search as well as the search suggestions while typing. How do I limit my function that shows the loading.gif to only show when it's a user AJAX search and not a search-suggestion-while-typing AJAX search?
This is my function:
$(document).ajaxStart(function () {
$(".se-pre-con").fadeIn("fast");
}).ajaxStop(function () {
$(".se-pre-con").fadeOut("fast");
});
how about bind it with condition like if user is still on the search input then dont show the loading.gif else if the user is out of the search input or first contact on the search input then show the loading.gif (refer below)
first the global variable
var input_focus = false;
and then when the specified input is on focus
$("#specified_input").focus(function(){
//set the variable named 'input_focus' to true to reject the showing of the loader (loading.gif) or hide it.
input_focus = true;
}).blur(function(){
//when the specified input lose it focus then set the variable 'input_focus' to false so that the loader (loading.gif) is allowed to show
input_focus = false;
});
$.ajax({
url : 'my-url',
type : 'post',
data : {},
beforeSend : function(){
//check if input is on focus
if(input_focus !== true){
//show the loading.gif, assume that #loader
$("#loader").show();
}else{
//hide the loading.gif, assume that #loader
$("#loader").hide();
}
},
complete : function(){
//when the ajax request is complete
},
success : function(response){
//the response function
}
});
I'd tackle it by either of the following:
1) Add a global variable such as showLoadingAnimation and set it to true or false depending on the need. Within your ajaxStart and ajaxStop do the following:
$(document).ajaxStart(function () {
if (showLoadingAnimation) $(".se-pre-con").fadeIn("fast");
}).ajaxStop(function () {
if (showLoadingAnimation) $(".se-pre-con").fadeOut("fast");
});
2) Instead of changing the jQuery global settings, Wrap the jQuery method with your own method:
//only listen to ajaxStop event so that we can hide the animation
$(document).ajaxStop(function () {
$(".se-pre-con").fadeOut("fast");
});
function myAjax(params, showAnimation) {
if (showAnimation) $(".se-pre-con").fadeIn("fast");
$.ajax(params);
}
//in your code you instead of calling $.ajax({...}) simply use `myAjax({...})`
Hope this helps.
Okay, pretty straight forward JQuery question that I am struggling to find an answer for:
I have a JQuery event that is called on button click:
$(document).ready(function(){
resetForms('reservation');
$('#form-reservation').submit(function(event){
event.preventDefault(); //the page will no longer refresh on form submit.
var resCheck = $(this).find('input[class="reservationid"]').val(); //now we have the reservation ID, let's perform our check.
document.cancel_res.cancel_agree.checked = false;
//document.cancel_res.cancel_agree.disabled = false;
document.cancel_res.cancel_button.disabled=true;
document.form_reservation.search_button.value="Searching...";
document.form_reservation.search_button.disabled=true;
$.ajax({
url: 'inc/searchres.php',
type: 'POST',
data: 'resid='+resCheck,
success: function(data){ //data is all the info being returned from the php file
resetForms('reservation'); //clear forms
document.form_reservation.search_button.value="Search Reservation";
document.form_reservation.search_button.disabled=false;
$('#reservation-id').val(resCheck); //add read ID back into text box
var jsonData = $.parseJSON(data);
//BLAH BLAH BLAH BLAH
}
});
});
});
The function works perfectly... however, is there anyway to call this function without utilizing the submit event? I tried to take out everything after the $('#form-reservation').submit(function(event){ call and place it in a separate function, and then call the function from the submit event. However, for whatever reason, this failed.
Basically, I want the submit event to still trigger this function, but I also want to be able to call the entire function under other circumstances. Thanks in advance!
It's actually pretty easy:
var MyFunc = function(event){
typeof event !== 'undefined' ? event.preventDefault() : false; //the page will no longer refresh on form submit.
var resCheck = $(this).find('input[class="reservationid"]').val(); //now we have the reservation ID, let's perform our check.
document.cancel_res.cancel_agree.checked = false;
//document.cancel_res.cancel_agree.disabled = false;
document.cancel_res.cancel_button.disabled=true;
document.form_reservation.search_button.value="Searching...";
document.form_reservation.search_button.disabled=true;
$.ajax({
url: 'inc/searchres.php',
type: 'POST',
data: 'resid='+resCheck,
success: function(data){ //data is all the info being returned from the php file
resetForms('reservation'); //clear forms
document.form_reservation.search_button.value="Search Reservation";
document.form_reservation.search_button.disabled=false;
$('#reservation-id').val(resCheck); //add read ID back into text box
var jsonData = $.parseJSON(data);
//BLAH BLAH BLAH BLAH
}
}
$(document).ready(function(){
resetForms('reservation');
$('#form-reservation').submit(MyFunc); //this calls on submit
});
//this calls without need of a submit
MyFunc();
I would simply trigger the handler.
$("#form-reservation").triggerHandler("submit");
http://api.jquery.com/triggerHandler/
As per the api docs, this does not cause the form to submit, it just run's the handlers bound to that event.
I have some jquery that looks like this,
$('.career_select .selectitems').click(function(){
var selectedCareer = $(this).attr('title');
$.ajax({
type: 'POST',
url: '/roadmap/step_two',
data: 'career_choice='+selectedCareer+"&ajax=true&submit_career=Next",
success: function(html){
$('.hfeed').append(html);
$('#grade_choice').SelectCustomizer();
}
});
});
My problem is that if the user keeps clicking then the .hfeed keeps getting data appended to it. How can I limit it so that it can only be clicked once?
Use the one function:
Attach a handler to an event for the elements. The handler is executed at most once per element
If you wanted the element to only be clicked once and then be re-enabled once the request finishes, you could:
A) Keep a state variable that updates if a request is currently in progress and exits at the top of the event if it is.
B) Use one, put your code inside a function, and rebind upon completion of request.
The second option would look like this:
function myClickEvent() {
var selectedCareer = $(this).attr('title');
var that = this;
$.ajax({
type: 'POST',
url: '/roadmap/step_two',
data: 'career_choice='+selectedCareer+"&ajax=true&submit_career=Next",
success: function(html){
$('.hfeed').append(html);
$('#grade_choice').SelectCustomizer();
},
complete: function() {
$(that).one('click', myClickEvent);
}
});
}
$('.career_select .selectitems').one('click', myClickEvent);
You can either use a global variable like
var added = false;
$('.career_select .selectitems').click(function(){
if(!added) {
// previous code here
added = true;
}
});
or use .one("click", function () { ... }) instead of the previous click function to execute the handler at most once per element. See http://api.jquery.com/one/ for more details.