How to implement a periodical page refresh with a failover - ajax

I am trying improve the fault tolerance in a JSP-page that is updated on a periodical basis. A timeout is used to keep track of when it is time to submit the page.
Problem is that the communication regularly fails which leaves us with a broken/missing page that won't refresh when the communication is up and running again.
The code below is the current implementation.
function startTimer(buttonid) {
var startstring = 'myTimer("' + buttonid + '")';
window.setTimeout(startstring,15000);
}
function myTimer(buttonid) {
window.document.forms[0].submit();
}
startTimer() is called in the onload event of the page.
<body onload="startTimer('blurp');
Best solution is a page that gracefully degrades when the communication is down. In that case it emits an error message and tries to refresh after a set period again.
I was looking at PeriodicalUpdater in Prototype as a way to solve this problem.

How about using a fake div to store the result of the ajax request, when you get a response then update the real div, when you get an error of communication than do nothing or signal to the client that the data in that div is old
new Ajax.PeriodicalUpdater($('fakeUpdateDiv'),
url, {
frequency : 30,
method : 'get',
parameters : {
},
onSuccess : function(transport) {
$('realUpdateDiv').update(transport.responseText);
},
onFailure : function(transport) {
//do something
}
});
PS: the fakeUpdateDiv is set to display:none

Related

Handling session timeouts in ajax calls

ASP.Net MVC 5 .Net Framework 4.6.1
I just added code to detect session timeout which works fine:
public class CheckSessionTimeOutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
var context = filterContext.HttpContext;
if (context.Session != null)
{
if (context.Session.IsNewSession)
{
string sessionCookie = context.Request.Headers["Cookie"];
if ((sessionCookie != null) && (sessionCookie.IndexOf("ASP.NET_SessionId", StringComparison.Ordinal) >= 0))
{
string redirectTo = "~/Home/Index";
filterContext.HttpContext.Response.Redirect(redirectTo, true);
}
}
}
base.OnActionExecuting(filterContext);
}
}
As you can see, I redirect them to the home screen. I have my [CheckSessionTimeOut] as an attribute on all pertinent controllers. So, I run the app, go to a page other than the home screen, wait 1 minute for session timeout, the code runs as expected in certain situations. Case and point, I have a dropdown and when a selection is made, a redirect is taking place. Heres the method:
$('#selusers').change(function () {
var rd = $(this).find("option:selected").attr('redirect');
location.href = rd;
});
What happens here is when a user is selected from the dropdown, the redirect attribute is read and redirection to that person takes place. If the session times out, redirection to the logged in user takes place and not the newly selected user. This is correct for my app.
However, I make numerous ajax calls in my app. When the session times out and I click on an element that fires an ajax call, I get redirected to the home screen, but the error method gets called in the ajax request. I get a popup with the home screen html inside of it. Here's one example of an ajax call I'm making. I'm on a screen with a save button, the session times out and this code gets fired:
SaveButtonClicked: function (somedata) {
$.ajax({
url: url,
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(some data im sending),
success: function (dataResult) {
if (!dataResult.Ok) {
alert("Error occurred. Please try again");
}
},
error: function (err) {
alert(err.responseText);//this gets called
}
});
}
I have overridden the default alert so styled html will appear. The alert box has the home screen html in it. I do not want that. I want the app to be redirected to the home screen, no popup. So my first question, is there a way to do something at the server to stop the ajax call from running its complete methods(i.e I want to do something at the server so the ajax call's success, error, or complete methods will never be called)? Next question if the first one isn't an option, what would be a very good way to detect that the session has timed out in the complete methods of an ajax call so the user is gracefully redirected to the home screen? If there are any other ways of doing what i'm trying to achieve that I didn't not ask, please share them. Thank you for reading my question.
UPDATE
I removed the error function from one of my ajax calls and added a global error handler instead:
$(document).ajaxError(function (e, xhr, settings) {
debugger;
});
Now, when the session timeout, this error handler gets called, BUT, i look in the xhr variable and it contains the results of the ajax call and corresponding html. The status is a 200, the statusText says parsererror, the readystate is a 4. There is nothing here that tells me the session timed out. What can i do at the global ajaxError method to tell me session timed out?
A good starting points might be:
If your ASP.NET MVC project properly returns status code:
$.ajaxSetup({
statusCode: {
401: function() {
window.location.href = "/login/path";
}
}
});
if not you can try:
$(document).ajaxError(function (e, xhr, settings) {
debugger;
});
Review e & xhr properties and make a decision from there.

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.

Spring MVC: Auto-save functionality (jQuery, Ajax...)

I'd like to implement a "auto-save" functionality on my page. I don't really know how to start though. I got one object (with a list of tasks). I'd like to submit the form every 20 seconds, so the users won't lose their data. It doesn't have to be exactly like that. After every submit the submit-button should be disabled as long as there are no changes.
I'm using Spring MVC. I did some research but I'm not an expert in jQuery, Spring... So it's all pretty complicated for me. A tip, or a working example would help me a lot.
It's a pretty complex form (a timesheet). There are +/- 50 textboxes on one page (minimum, depends on the number of tasks available)
Thanks.
I don't know what spring mvc is, but in ASP.NET MVC I would do the following:
I assume all your data is in a form, you give the form an ID, then post it:
$(function () {
var timer = 0;
$(this).mousemove(function(e){
timer = 0;
});
$(this).keypress(function() {
timer = 0;
});
window.setInterval(function () {
timer++;
if (timer == 20) {
$('#form').submit(function() {
});
}
}, 1000);
});
Checks for mousemove, keypress, if this isnt done in 20 seconds then it saves the form.
Edit: What you could also do maybe is, after every textbox they fill in, post the data: as followed:
http://api.jquery.com/change/
$('.textbox').change(function() {
$.ajax({
url: '/Save/Textbox',
data: 'TextBoxId=' + $(this).id + '&TextValue=' + $(this).value
});
});
In this example, you make a controller called Save, action called Textbox, you give the textbox the ID of data that it has to save, and on change (after un focussing the textbox), it posts the textbox id, and the value of the box.
then in the controller you retrieve it:
public void SaveText(string TextBoxId, string TextValue) {
// SAVE
}
Below Js script will help you to make ajax call when ever form field changes.
<script>
$(document).ready($('.form-control').change(function() {
$.ajax({
type : "post",
url : "http://localhost:8521/SpringExamples/autosave/save.htm",
cache : false,
data : $('#employeeForm').serialize(),
success : function(response) {
var obj = JSON.parse(response);
$("#alert").text(JSON.stringify(obj));
$("#alert").addClass("alert-success");
},
error : function() {
alert('Error while request..');
}
});
}));
</script>

Ajax.BeginForm switches from async to sync

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?

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