Ajax.BeginForm switches from async to sync - ajax

I'm running into an issue with an async call to the server that only works one time, then it appears to become a synchronous call. Let me try to explain.
It's an MVC 2.0 site, using ASP.NET and Ajax. I'm using the Ajax.BeginForm helper, like so:
<% using (Ajax.BeginForm("Start", null,
new { virtualMachineId = xyz },
new AjaxOptions { UpdateTargetId = "VirtualMachineForm", OnBegin="OnStartingVm" }
)){
Then while the machine is starting I want to call back to the server and get an update every second. It works the first time correctly, then changes behavior. OnStartingVm looks something like this:
function OnStartingVm() {
$('#StartingDiv').css('visibility', 'visible');
$('#StartingDiv').show();
var vmId = xyz;
intervalId = setInterval(function () {
updateStartingStatus(vmId)
}, 1000);
}
function updateStartingStatus(vmId) {
/* This part always runs */
$.ajax({
url: "/member/vm/getstartingstatus/" + vmId,
dataType: 'json',
async: true,
success: function (data) {
alert('This part runs every second on the first time only');
if (data.status == "Running") {
$('#StartingDiv').text(data.percentComplete);
}
else {
$('#StartingDiv').css('visibility', 'hidden');
$('#StartingDiv').hide();
clearInterval(intervalId);
}
},
});
}
Within the updateStartingStatus function, the first part runs every second, every time. However, within the Ajax call, the success result works every second on the first time only. Then on the second time I click on the start button all of the requests queue up. After the starting has completed, about 20 seconds later, I get a bunch of alert windows back to back. So, I can tell that updateStartingStatus runs every second every time, but the ajax call appears to switch to become a sync call after the first time.
Refreshing the browser window doesn't help. I have to fully close it and open it again. The same occurs in IE and Chrome.
One more thing to note is that the updated div (VirtualMachineForm) contains most of the page, including the button being pressed. So it basically replaces the page from under itself. Not sure if that would cause any issues.
Additionally, if I debug in Visual Studio 2010, the call isn't made to the controller action when the issue occurs. So, it appears to be something client-side. I've ruled out any issues server-side.

I eventually figured it out. This post lead to the answer.
It was session state related and the browser locked the request until a previous one was completed. I didn't need to disable session state, but I had to avoid a session write from code.
That explains why a browser refresh didn't work and why I had to close and open the browser again.

Why don't you call clearInterval function?

Related

Is it possible to fire multiple ajax requests asynchronously in Magento 2 backend?

What the title says.
Im trying to run an import script with AJAX "call 1" and I want to keep track of the import (for feedback purposes) with AJAX "call 2".
To give the end user live feedback these calls need to run simultaneously and "call 2" needs to call itself (recursive) to poll for changes.
I have the Controllers and the calls and everything works just fine, just not at the SAME time.
Is it a soft lock on the database or is it something else?
Btw I am aware of the "async: true" setting for the ajax call.
[edit]
It looks like Magento is preventing me from executing two controllers at the same time. Can anyone confirm this?
I think you cannot do two AJAX requests concurrently. This means you always needs to have a logical order, a.k. first 'call 1', then 'call 2'. If you want to make sure call 2 always fires after the call 1 just put it in the success method.
Like so:
$.ajax({
url: "test-to-call-1",
context: call-1-context
}).done(function() {
$.ajax({
url: "test-to-call-2",
context: call-2-context
}).done(function() {
Now both ajax requests are done.
And you could add the context of the first one to the second call.
});
});
If you want to enable polling, just place a setTimeOut loop in which you do the second AJAX call :)
Like this:
function start_polling(counter){
if(counter < 10){ // poll maximum of 10 times.
setTimeout(function(){
counter++;
$.ajax({
url: "test-to-call-2",
context: call-2-context
}).done(function() {
start_polling(counter);
Now both ajax requests are done.
And you could add the context of the first one to the second call.
}).error(function(){
start_polling(counter);
});
}, 1000);
}
}
$.ajax({
url: "test-to-call-1",
context: call-1-context
}).done(function() {
start_polling(0)
});
Well I figured it out.
All I had to do was set:
session_write_close();
In front of the method that started the import and I could start polling with a second AJAX call!
This is probably frowned upon, but it works

Website loses performance after some jQuery $.ajax calls

I admit I'm quite noob with full ajax websites, and so I'm surely making some mistakes.
The problem is this:
in http://lamovida.arabianessence.com
every page is loaded with an $.ajax call using this function
function getAjaxPage() {
$('a.ajaxc').click(function() {
$("li.page_block").find(".wrapper").fadeOut(400).remove();
hideSplash();
var $thishref = $(this).attr('href'),
$thisurl = $thishref.replace("#!/",""),
$urlArr = $thisurl.split('-'),
$urlOk = $urlArr[0],
$dataOk = $urlArr[1];
$.ajax({
url : $urlOk + ".php",
data : 'id='+$dataOk,
success : function (data,stato) {
$("#content").css({opacity:1}).fadeIn(400);
$("li.page_block").html(data);
$("li.page_block").css('visibility', 'visible');
$("li.page_block").find(".wrapper").css({opacity:0}).show().animate({opacity:1},1000);
var $whgt = $(".wrapper").height(),
$ctop = ( ( $(window).height() - $whgt ) /2 )-40;
$("#content").stop().animate({height: $whgt+40, top: $ctop},1000);
$("li.page_block").css('padding-top',20);
$('.scrollable').jScrollPane();
$('.slider>ul>li').jScrollPane();
getAjaxPage();
},
error : function (richiesta,stato,errori) {
alert(errori);
}
});
});
}
Every time this function is called the content gets loader slower, and after about 20 clicks things get real bad, and the loading time grows and grows.
I tried to analyze the situation using the Google Chrome's Timeline, and I saw that after each click the browser uses more memory. If I comment the getAjaxPage(); row in the "success" section the situation starts to get better, but of course I lose all the internal navigation.
What could I do to avoid this problem?
Many thanks to all!
Every call to $('a.ajaxc').click() is adding new event handler thus every click causes more requests to be made. After the first click, every click will cause two requests. Another click? Another three requests. Etc.
Put the handler outside the function and you will have only one AJAX call per click:
$(document).ready(function() {
$('a.ajaxc').click(getAjaxPage);
});
I also don't see the reason behind calling getAjaxPage again from within the callback, so remove it as well to avoid infinite loop of requests.

Detect AJAX Request

On my website I have mouse over and mouse out events set up on an HTML table. These events trigger ajax requests, and perform certain actions etc. However, i want to be able to not trigger a second request if one is already running. So, is there away to detect these requests, and therefore avoid a second. Incidentally Im using the jQuery $.ajax()
if it helps at all.
Thanks in advance
Chris
I'd try something simple like:
var requestMade = false;
function yourAjaxFunction(){
if(!requestMade)
{
requestmade = true;
$.ajax({
url: "page",
success: function(){
requestMade = false;
}
error: function(){
requestMade = false;
}
});
}
}
You can use the success: and error: settings to change the variable back to false.
I have never used the error so you may have to include some other things in it, but this is the general idea.
For this suppose I'd use ajaxStart() and ajaxStop() which would change specific variable ajaxRunning which could be checked before sending the request (maybe in ajaxStart() directly?)
Set global or local static variable to true when first ajax is about to trigger, than add if before triggering the second one ;) Than after one request is finished, set this variable to false

jQuery Async Call only "parallel" when URL's different

I was playing with jQuery and async calls last night and found an unusual issue. I wanted to run multiple Ajax calls inside a loop. I wrote the below (where rand.php just sleeps for a second and returns a random number). Somewhat surprisingly it executes synchronously and takes 20 seconds or so to finish.
$(document).ready(function () {
$([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]).each(function() {
var number = this;
$.get("rand.php", function(data) {
$('#'+number).html(data);
});
});
});
The PHP code is as follows,
<?php
sleep(1);
echo rand();
?>
I was thinking this is clearly wrong as the async calls should be no blocking and return almost in parallel. After much playing around (assuming it was a server issue) I discovered that appending anything to the URL to make it look like it was different worked as expected. That is it returned in 3 seconds or so (6 or so calls at a time).
$(document).ready(function () {
$([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]).each(function() {
var number = this;
$.get("rand.php?"+number, function(data) {
$('#'+number).html(data);
});
});
});
I don't suppose a jQuery/Javascript Guru can explain this behavior? Is it some browser limitation? Why is it that only when the URL's are different that it runs as I would expect?
EDIT - Rather then reply, this was using Chrome (whatever the latest is) and Firefox 5/6. I did try it in IE which did cache it, so ignored that and focused on Chrome. Interesting the first one works as expected in IE9 on the first page load, but then just displays cached results when reloaded.
You are in ie aren't you. Bad! Bad IE user! IE caches get requests as if it was any other content. Jquery has a built in function to address this:
$.ajaxSetup({ cache : false });
This will add a nifty spoiler to take care of this. But why add the spoiler in other browsers? So usually I do this:
if(!+"\v1"){
$.ajaxSetup({ cache : false });
}
Which is the tests for IE and set it only in that browser.

Can I make an Ajax request inside an ongoing Ajax request (e.g. on the success callback function)?

I have a jQuery application, a shopping cart, that posts back info to the server, if the text inputfield is changed. This is done in an Ajax request. Now, if the Ajaxrequest is a success, I want to reload the shoppingcart asynchronously. The code is as follows:
$(document).ready(function() {
var jInput = $(":input");
jInput.change(function() {
var vareAntal = $(this).val();
var vareID = $(this).siblings("input#vareID").val();
$.ajax({
type: 'POST',
url: 'checkout.aspx',
data: { 'ID': vareID, 'Antal': vareAntal },
success: function() {
$("#newbasket").load(location.href + " #newbasket>*", "");
}
});
});
});
This works, but only once! If I change the text inputfield, after the page is loaded for the first time, the div with the ID of newbasket reloads asynchronously. But if I try to change it again, nothing happens.
I've tried to do some debugging with Firebug, and the first time I change the text inputfield, it fires a POST-event, and afterwards a GET-event, when the POST-event is succesful. But after that, nothing happens when I change the text inputfield again.
So, how do I achieve triggering the .load() method after each text input change?
I've also tried experimenting with the .ajaxComplete() function, but that, of course, resulted in an infinite loop, since the .load() is an ajax-object.
Instead of .change(func), use .live('change', func) here, like this:
jInput.live('change', function() {
This will make the selector work on any new inputs added as well. When you're replacing the elements like you are currently, their event handlers are lost (or rather, not re-created, because you have new elements). .live() is just for this purpose, it listens for events from old and new elements, regardless of when they were added.

Resources