I have form autocomplete code that executes when value changes in one textbox. It looks like this:
$('#myTextBoxId)').change(function () {
var caller = $(this);
var ajaxurl = '#Url.Action("Autocomplete", "Ajax")';
var postData = { myvalue: $(caller).val() }
executeAfterCurrentAjax(function () {
//alert("executing after ajax");
if ($(caller).valid()) {
//alert("field is valid");
$.ajax({ type: 'POST',
url: ajaxurl,
data: postData,
success: function (data) {
//some code that handles ajax call result to update form
}
});
}
});
});
As this form field (myTextBoxId) has remote validator, I have made this function:
function executeAfterCurrentAjax(callback) {
if (ajaxCounter > 0) {
setTimeout(function () { executeAfterCurrentAjax(callback); }, 100);
}
else {
callback();
}
}
This function enables me to execute this autocomplete call after remote validation has ended, resulting in autocomplete only when textbox has valid value. ajaxCounter variable is global, and its value is set in global ajax events:
$(document).ajaxStart(function () {
ajaxCounter++;
});
$(document).ajaxComplete(function () {
ajaxCounter--;
if (ajaxCounter <= 0) {
ajaxCounter = 0;
}
});
My problem is in IE (9), and it occurs only when I normally use my form. Problem is that function body inside executeAfterCurrentAjax(function () {...}); sometimes does not execute for some reason. If I uncomment any of two alerts, everything works every time, but if not, ajax call is most of the time not made (I checked this by debugging on server). If I open developer tools and try to capture network or debug javascript everything works as it should.
It seems that problem occurs when field loses focus in the same moment when remote validation request is complete. What I think it happens then is callback function in executeAfterCurrentAjaxCall is executed immediately, and in that moment jquery validation response is not finished yet, so $(caller).valid() returns false. I still do not know how alert("field is valid") helps in that scenario, and that could be sign that I'm wrong and something else is happening. However, changing executeAfterCurrentAjaxCall so it looks like this seems to solve my problem:
function executeAfterCurrentAjax(callback) {
if (ajaxCounter > 0) {
setTimeout(function () { executeAfterCurrentAjax(callback); }, 100);
}
else {
setTimeout(callback, 10);
}
}
Related
This is my ajax function
function repeatedCall() {
$.ajax({
url: '/getUrl',
complete: function(data) {
if (data.statusText != "error") {
//my actions
}
}
})
}
setInterval(repeatedCall, 5000); //To make repeated ajax calls
function updateData_function{
//I want to abort all previous ajax calls and make a new ajax call since it will update the data
}
I can use clearInterval but the pending calls are not getting aborted and hence it is not updating properly.
How can i make repeated calls and at the same time abort all the requests if it enters my updateData_function.
This updateData_function will have new values so i need to make fresh ajax request.
How can i do this? Please help!! Thanks a lot in advance!!
Using setInterval to make repetead calls is not a good practice. Assume that your previous request is not completed, then there is no point in making the same ajax call. Also, as you may know, there are possibility that the response from the previous ajax call can come after the recent ajax response. So it is always better to abort any previous ajax calls.
I think the below solutions may solve your issue:
Solution 1: Just Extentending what you have done:
var xhr
function repeatedCall() {
if(xhr){
// abort any previous calls, to avoid any inconsistency
xhr.abort()
}
xhr = $.ajax({
url: '/getUrl',
complete: function(data) {
if (data.statusText != "error") {
//my actions
}
}
})
}
setInterval(repeatedCall, 5000)
function updateData_function {
//I want to abort all previous ajax calls and make a new ajax call since it will update the data
if(xhr){
xhr.abort()
}
}
Solution 2: What I feel is a better approach
var xhr;
function repeatedCall() {
xhr = $.ajax({
url: '/getUrl',
complete: function(data) {
if (data.statusText != "error") {
//my actions
// Call the ajax call again:
setTimeout(repeatedCall, 5000)
}
}
})
}
function updateData_function {
//I want to abort all previous ajax calls and make a new ajax call since it will update the data
if(xhr){
xhr.abort()
}
// do something
}
// somewhere - to initiate the repeatedCall for the first time
repeatedCall()
I faced the same problem before as well and I was sending to many ajax calls on keyup which was leading my website to collapse. I found out the solution to setTimeout(); in to the ajax all firing and keeping firing the function clears timeout and settimeout again. This let you to fire ajax only 1 time on pressing to many time.
Edit: Ok for example I had a searchbox which was getting predefined suggestions with ajax call with onkeyup function. as I was start typing it was firing ajax call again and again and stucking. I started to cancel the one before as I firing another so fixed the situation. Here is the DEMO Doesnt matter how many time you hit the button it fires only one.
I've modified my code and this works
abortValue = false;
var xhr;
xhrPool = [];
var trying;
function abortAjax() {
$.each(xhrPool, function(idx, jqXHR) {
jqXHR.abort();
});
}
$(document).ready(function() {
fn = function() {
xhr = $.ajax({
url: '/getUrl',
beforeSend: function(jqXHR) {
xhrPool.push(jqXHR);
},
complete: function(jqXHR, data) {
if (abortValue == true) {
abortAjax()
} else {
if (jqXHR.statusText != "error" && "undefined") {
//myactions
}
}
}
});
};
var interval = setInterval(fn, 5000);
});
function updateData_function {
//I want to abort all previous ajax calls and make a new ajax call since it will update the data
abortValue = true;
abortAjax();
abortValue = false;
fn();
}
I have some problem debugging a script, just because in debug mode all works fine... but not in runtime:
I have this function in javascript:
function Add() {
...
$('#Value').val($('#Value').val()); // Value is a div class="input"
...
$.get('#Url.Action("GetSomeData", "_Shared")', { id: parseInt($('#DataID').val()) },
function (result) { $('#SomeData').val(result); });
if ($('#SomeData').val() == "x") {
$('#tmp').val($('#Value').val());
}
else {
$('#tmp').val("0");
}
...
}
and the controller _Shared simply returns an attribute:
public string GetSomeData(int id)
{
return unitOfWork.DataRepository.GetByID(id).Something;
}
What happens is when I use a breakpoint in the "if", $('#SomeData').val() has the correct value but if I remove the breakpoint, write a console.log($('#SomeData').val()) and execute, it is alway empty and the $('#tmp').val() is always "0".
Can anybody tell me what I'm doing wrong?
This is a synchronicity issue. $.get is asynchronous, and the callback you pass it will run when it is finished, not inline with the code where it is written. So your function (result) { $('#SomeData').val(result); }); is running after your if ($('#SomeData').val() == "x") {...
You can fix this by adding the code to run after the $.get to the callback:
$('#Value').val($('#Value').val()); // Value is a div class="input"
...
$.get('#Url.Action("GetSomeData", "_Shared")', { id: parseInt($('#DataID').val()) },
function (result) {
$('#SomeData').val(result);
if ($('#SomeData').val() == "x") {
$('#tmp').val($('#Value').val());
}
else {
$('#tmp').val("0");
}
});
...
Note, it works when you add the breakpoint because that gives your asychronous $.get time to finish and execute.
Did you put the event binding on Jquery on load event?
$(function(){
//Your code here
});
If not, maybe in the runtime, jquery had not found your element (#Value) yet, so it will return empty value.
Ok, I've found a workaround to this asynchronicity situation:
$.get('#Url.Action("GetSomeData", "_Shared")', { id: parseInt($('#DataID').val()) },
function (result) {
if (result == "x") {
$('#tmp').val($('#Value').val());
}
else {
$('#tmp').val("0");
}
$('#SomeData').val(result);
});
Testing inside the function works like a charm. Thanks for the clues.
I wanted to make an ajax call, and then wait for the response from ajax call (Stop form submission till then) and then post the form based on the ajax response that I get. This question is based on Make ajax call and then submit form. So, after putting below script, everything works fine, but I lose the client side validation. Can I make an ajax call and still respect the Client Side validation?
#section scripts {
<script>
var canSubmit = false;
$('form').submit(function (e) {
if (!canSubmit) {
e.preventDefault();
var data = $('form').serialize();
var url = $(this).data('url');
$.ajax({
url: url,
type: 'POST',
data: data,
success: function (response) {
if (response.hasPreviousRequest) {
if (confirm("You've already applied for this job. Apply again?")) {
canSubmit = true;
$('form').submit();
}
}
else {
canSubmit = true;
$('form').submit();
}
},
error: function () {
alert("error");
}
});
}
});
</script>
}
P.S: Kindly note that as soon I as remove the ajax call Client side validation starts working fine. Can some one please explain me this behaviour?
You need to call the .valid() method on the form element (and if not, then cancel the ajax call)
$('form').submit(function (e) {
if (!$(this).valid()) {
return // exit
}
if (!canSubmit) {
....
I'm using ajax for my form because I don't want the page to reload after submit.
Now is everything working but the only problem is that the ajax script runs everytime I click the submit button.
I thought I could just paste the ajax in my if statement that tells when to run and when not, but it doesn't work.. anyone have any idea why?
theForm.onsubmit = function() {
if (pion == 1 || myName.value.length == 0 || myMessage.value.length == 0) {
if (pion == 1 || emailValid.value.length == 0) {
emailValid.style.border = "1px solid red";
myError.innerHTML = "U heeft geen geldig e-mail adres ingevoerd.";
}
if (myName.value.length == 0) {
myName.style.border = "1px solid red";
myError.innerHTML = "U heeft geen naam ingevuld.";
}
if (myMessage.value.length == 0) {
myMessage.style.border = "1px solid red";
myError.innerHTML = "U heeft geen bericht ingevuld.";
}
return false;
}
else {
// the ajax I found somewhere, that works but not in this if/else statement
$(function () {
$('form').bind('submit', function () {
$.ajax({
type: 'post',
url: 'mail.php',
data: $('form').serialize(),
success: function () {
alert('form was submitted');
}
});
return false;
});
});
return true;
}
}
This code block:
$('form').bind('submit', function () {
$.ajax({
type: 'post',
url: 'mail.php',
data: $('form').serialize(),
success: function () {
alert('form was submitted');
}
});
return false;
});
bound the function that sends the AJAX request to your form element's submit event. Once it did, the function remains bound forever (or at least until you explicitly unbind it). That's why once your code falls in the else statement for the first time, the AJAX request will be sent every time the form is submit.
That said, your if/else logic should be inside the function that is bound to your form's submit event in order to send the AJAX request conditionally. Something like:
$('form').bind('submit', function () {
if (etc etc etc) {
// do other things
}
else {
// send AJAX
$.ajax({
type: 'post',
url: 'mail.php',
data: $('form').serialize(),
success: function () {
alert('form was submitted');
}
}
});
return false;
});
// the ajax I found somewhere
Copying/pasting code into your project without any knowledge of what that code does is a famously bad idea.
This code doesn't make an AJAX call:
$(function () {
// anything in here
});
What this code does is tell jQuery to execute that function when the document is ready. But presumably the document is already ready when you invoke this, since it's happening on a form submit event.
At best, depending on how the internals of jQuery works, it might be executing that inner function immediately. But still, you don't need that wrapping call to jQuery.
But then, what is that function doing?:
$('form').bind('submit', function () {
// anything in here
});
Again, it's not actually executing any AJAX code. All this is doing is binding a function to the form's submit event. That function may contain AJAX code (and in this case it does), but that's not being executed here. It will be executed when the form is next submitted.
But, you're doing this every time you submit the form. So what's happening is:
User presses submit, nothing visibly happens. 1 event handler is bound to the next submit event.
User presses submit, 1 event handler (AJAX) is executed, 2 event handlers are now bound to the next submit event.
User presses submit, 2 event handlers (AJAX) are executed, 4 event handlers are now bound to the next submit event.
and so on...
If you want to call the AJAX code in the else block, then just call it in the else block:
if (/* ... */) {
// ...
} else {
$.ajax({
type: 'post',
url: 'mail.php',
data: $('form').serialize(),
success: function () {
alert('form was submitted');
}
});
}
function checkuser(user) {
var ret = false;
$.ajax({ type:'POST', url:'user.php',
async:false,
data:{'user':user},
success:function (data) {
if (data == 1) ret = true
} });
return ret;
}
I use bvalidator to validate fields. It seems to fire this function on every keypress and the user is not able to continue typing before the ajax call is competed. I'm not really sure what to do here.
How could I make the function not be ran more than once every two seconds for example?
You need to get rid of async:false but you also need to modify your code to work asynchronously. The synchronicity is what is causing your UI to 'freeze'.
Maybe you could try setting a timeout that will run 2 seconds after a key is pressed on your input, but if another key is pressed it restarts that timer. So in essence it will only after two seconds of no keystrokes.
var validateTimeout;
$('#target').keydown(function() {
clearTimeout(validateTimeout);
validateTimeout = setTimeout(function(){checkuser(user);},2000);
});
You'll need to update the checkuser ajax call to have a smarter callback to work async:
function checkuser(user) {
$.ajax({ type:'POST', url:'user.php',
async:false,
data:{'user':user},
success:function (data) {
if(data == 1){
//something to indicate sucess
}else{
//something to indicate failure
}
} });
}
You could throttle the call with a throttle plugin:
jQuery Throttle Plugin