jQuery + Ajax + Loading Spinner Image = Too Fast! - asp.net-mvc

I'm using jQuery in my ASP.NET MVC 2 page. It's a super simple post that gets a date in return. The process itself runs very quickly. I want to use a spinner image to show the user something is going on. All works fine in Firefox, testing locally. However, in IE 8, the spinner image doesn't display long enough; it just flickers. This might confuse the end user if they do not see an indication that the process is working/done. What would be the best way to fix this problem?
Thanks.
<img id="signedout<%: item.Id %>" src="/Content/Images/signed_out.png" alt="Signed Out" title="Signed Out" style="display:none" />
<div id="ajaxloader<%: item.Id %>" style="display:none;text-align:center"><img src="/Content/Images/ajax-loader.gif" alt="loading..." title="loading..." /></div>
<script type="text/javascript">
$(function () {
var id = "<%: item.Id %>";
$("#signout" + id).click(function () {
if (confirm("Are you sure you want to sign this visitor out?")) {
$(this).hide();
//$("#signout" + id).hide();
$("#ajaxloader" + id).show();
var url = '<%: Url.Action("signout") %>';
$.ajax({
type: "POST",
url: url,
data: "id=" + id,
success: function (result) {
$("#timeout" + id).append(result);
$("#ajaxloader" + id).hide();
$("#signedout" + id).show();
$("#row" + id).css("background", "#E8E8E8");
},
error: function () {
alert("There was an unexpected error. Please try again later.");
$("#ajaxloader" + id).hide();
$("#signout" + id).show();
}
});
}
});
});
</script>

It would probably be a better idea to give some other indication that the process has finished rather than misleadingly displaying the spinner when nothing is actually being processed. However you seem set on this.
This is based on amurra's answer and is designed to either hide the spinner once the process is loaded if and only if the timeout has already been returned. Therefore, if the AJAX request returns "too fast" it will wait for the timeout.
var timeoutComplete=false;
var requestComplete=false;
function HideLoadingSpinner() {
if(requestComplete) {
$("#ajaxloader" + id).hide();
} else {
timeoutComplete=true;
}
}
Meanwhile, inside the click handler...
setTimeout(HideLoadingSpinner, 2000);
$.ajax({type: "POST",
url: url,
data: "id=" + id,
success: function (result) {
$("#timeout" + id).append(result);
$("#signedout" + id).show();
$("#row" + id).css("background", "#E8E8E8");
if(timeoutComplete) {
$("#ajaxloader" + id).hide();
} else {
requestComplete=true;
}
},
error: function () {
alert("There was an unexpected error. Please try again later.");
$("#ajaxloader" + id).hide();
$("#signout" + id).show();
}
});
EDIT: I just removed the if(timeoutComplete) stuff from the error function, since there will be an alert before it anyway.

You could set a timeout in js and that would guarantee that the spinner wouldn't be hidden till after the timeout had expired:
function HideLoadingSpinner() {
$("#ajaxloader" + id).hide();
}
Then replace your ajax call with this one:
$.ajax({type: "POST",
url: url,
data: "id=" + id,
success: function (result) {
$("#timeout" + id).append(result);
setTimeout(HideLoadingSpinner, 2000);
$("#signedout" + id).show();
$("#row" + id).css("background", "#E8E8E8");
},
error: function () {
alert("There was an unexpected error. Please try again later.");
setTimeout(HideLoadingSpinner, 2000);
$("#signout" + id).show();
}
});
You could also move the other logic in the success callback into the HidingLoadingSpinner function if you get weird behavior due to the timer.

Can't you just show "Data loaded" message in bright background with fades off in few seconds after reload?

I've seen this before. Actually what you're seeing is IE taking a normal amount of time to run the request and FF taking longer than it should. You can set network.dns.ipv4OnlyDomains to localhost in about:config to dramatically speed up FF on localhost. Source.
In my own applications, I follow #Im0rtality's suggestion and have a notification that an ajax request is complete and show a spinner while it's happening. Many times I don't even see the spinner. I use a custom implementation of JBar for my notifications which is very professional looking.
As far as showing a spinner during AJAX calls, you include this in your master page to show a spinner during all JQuery AJAX calls:
$(function () {
$('.spinner')
.hide()
.ajaxStart(function () {
$(this).show();
})
.ajaxStop(function () {
$(this).hide();
});
});
Then you don't have to include showing and hiding the spinner w/ every call to $.ajax.

Related

Loading failed error

I am getting Loading failed error when searching for something in a select2 box using ajax. My code is as follows:
$("#drugSearch").select2({
placeholder: "Search for a drug by drug id or name",
minimumInputLength: 3,
ajax: {
url: "#Url.Action("SearchDrug", "Drug")",
dataType: 'jsonp',
quietMillis: 100,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
debugger;
return {
results: data.drugs
};
}
},
formatResult: drugResult,
formatSelection: drugSelection,
escapeMarkup: function (m) { return m; }
});
function drugResult(drug) {
debugger;
return drug.Name + " (" + drug.DrugBankRef + ")";
}
function drugSelection(drug) {
debugger;
return drug.Name + " (" + drug.DrugBankRef + ")";
}
The breakpoints are also not hitting the above debugger; lines
My JSON is returned as:
{ drugs: {[...]} }
It also has the properties Name and DrugBankRef and I have confirmed a valid JSON is returned from the URL after searching.
What am I doing wrong here? Anything else you need to trace the issue?
I was using JSONP instead of JSON, changing the data type to JSON fixed the issue.
It is not an error. There is a real difference between JSON and JSONP. In JSONP, your JS will send in a supplementary parameter, named callback, that contains the name of expeted enclosing function name.
Select2 supports the two modes :
JSON, which expects { drugs: {[...]} } as data
JSONP, which provide a callbackName and expects callbackName({ drugs: {[...]} }); as data
Both works, and are correct, differents, way of processing.
Feel free to read http://en.wikipedia.org/wiki/JSONP

JQM Nested Popups

I am having a hard time with the new Alpha release of JQM not showing nested popups. For example, I am displaying a popup form that the user is supposed to fill out, if the server side validation fails, I want to display an error popup. I am finding that the error popup is not being shown. I suspect that it is being shown below the original popup.
function bindSongWriterInvite() {
// Bind the click event of the invite button
$("#invite-songwriter").click(function () {
$("#songwriter-invite-popup").popup("open");
});
// Bind the invitation click event of the invite modal
$("#songwriter-invite-invite").click(function () {
if ($('#songwriter-invite').valid()) {
$('#songwriter-invite-popup').popup('close');
$.ajax({
type: 'POST',
async: true,
url: '/songwriter/jsoncreate',
data: $('#songwriter-invite').serialize() + "&songName=" + $("#Song_Title").val(),
success: function (response) {
if (response.state != "success") {
alert("Should be showing error dialog");
mobileBindErrorDialog(response.message);
}
else {
mobileBindErrorDialog("Success!");
}
},
failure: function () {
mobileBindErrorDialog("Failure!");
},
dataType: 'json'
});
}
});
// Bind the cancel click event of the invite modal
$("#songwriter-invite-cancel").click(function () {
$("#songwriter-invite-popup").popup("close");
});
}
function mobileBindErrorDialog(errorMessage) {
// Close all open popups. This is a work around as the JQM Alpha does not
// open new popups in front of all other popups.
var error = $("<div></div>").append("<p>" + errorMessage + "</p>")
.popup();
$(error).popup("open");
}
So, you can see that I attempt to show the error dialog regardless of whether the ajax post succeeds or fails. It just never shows up.
Anyone have any thoughts?
Mike
I found a solution!
I set a delay on the bindErrorPopup function to wait until the popup close animation completes.
function mobileBindErrorDialog(errorMessage, delay) {
var error = $("<div></div>").attr({
'data-rel': "popup",
'data-theme': "a"
});
$(error).append("<p>" + errorMessage + "</p>")
.popup({
overlayTheme: "a",
positionTo: "window",
theme: "a"
});
setTimeout(function () {
$(error).popup("open");
}, delay);
}
Works awesome!

Phonegap MobileJQuery AJAX Posts Twice while debugging

Hope there is some out there that can help!,
While debugging a WCF service that a phonegap application connects to it seems to post twice.
When the application runs normally no Break points etc it all works fine and i only receive 1.
It appears to me that ajax reposts itself if no response is returned from the server after a few seconds.
I will need to confirm this threw wireshark but just wanted to know if anyone else has come accross this before.
$.ajax({
type: "POST",
url: ServicePATH ,
data: JSON.stringify({ objs: arrayobj, parm2: var2, parm3: var3, parm4: 1 }),
contentType: "application/json",
dataType: "json",
success: function (data, textStatus, jqXHR) {
CallonSuccess(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log('error ' + textStatus);
console.log('XMLHttpRequest ' + XMLHttpRequest);
var str = '';
for (prop in XMLHttpRequest) {
str += "prop " + prop + " value :" + XMLHttpRequest[prop] + "\n"; //Concate prop and its value from object
}
console.log(str);
console.log('errorThrown ' + errorThrown);
console.log('passing ' + JSON.stringify({ objs: arrayobj, parm2: var2, parm3: var3, parm4: 1 }));
}
}).done(function () { console.log('Finished ajax'); });
Thanks Lmac
Perhaps no solution (see update below) for you but the same behaviour here.
Without the jquery Mobile framework everything works okay, with the framework embedded it fetches my json file a second time. In Chrome's Console you can see it under Network: GET status 200 and GET status 304 (not modified).
I have the option to throw out jQuery Mobile and I surely will. But would be also interested in knowing what's happening there.
UPDATE:
I had the xmlhttprequest within the $(document).ready(function() { }); It seems as if both jQuery and jQuery Mobile react to that.
If I put the script at the end of the site and make my xmlhttprequest outside the ready-method it fetches my json file only once.

Can someone explain to me a few thing about this JQuery code I have here from the MVC Music Store tutorial

The thing that confuses me somewhat and it's probably due to the conventions in
the jquery ajax() request .post() function is that it does not indicate anywhere that if request is successful that it should call the handleUpdate() function which gets the returned json object via "var json = context.get_data();", also why is the whole chunk of code starting with "if (data.ItemCount == 0)" in the handleUpdate() identical to the one in the .post() on success run > function (data) { duplicate code } .
Maybe because function (data) {} is callback function it waits for the entire request/response cycle to finish and that includes "var json = context.get_data();" in handleUpdate() ?
Thanks..
Pasted from the tutorial PDF, no other jscript in this view.
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '')
{
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0)
{
$('#row-' + data.DeleteId).fadeOut('slow');
}
else
{
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
function handleUpdate()
{
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
if (data.ItemCount == 0)
{
$('#row-' + data.DeleteId).fadeOut('slow');
}
else
{
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
</script>
The handleUpdate() function is a relic from the previous MVC2 version of the tutorial where the Ajax for removing items from the cart was handled by Microsoft's Ajax called via an Ajax.ActionLink helper. (see below)
This was changed to use JQuery Ajax in the MVC3 version of this tutorial but the handleUpdate() code has been left in it seems by mistake during the conversion from MVC2 to MVC3.
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function handleUpdate(context) {
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
$('#row-' + data.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + data.CartCount + ')');
$('#update-message').text(data.Message);
$('#cart-total').text(data.CartTotal);
}
</script>
...
<%: Ajax.ActionLink("Remove from cart", "RemoveFromCart",
new { id = item.RecordId },
new AjaxOptions { OnSuccess = "handleUpdate" })%>
There is no way (according to this code) that handleUpdate is being called on success of $.post. Jquery post function has following syntax
$.post(url,data, callback);
and in the code you can see that all three parameters are explicitly specified and callback is an anonymous function with signature
function(data){}
Now, what you can see is that this anonymous function and handleUpdate are doing exactly the same logic. That makes me believe that they belong to the two different scenarios. For example, first scenario is that links are rendered using
Html.ActionLink(LinkText, ActionName, new{#class = "RemoveLink"})
In this case click event is handled by jquery function on the top and all the logic is done in this function (including ajax and callback). Second function might have been used for some
//please confirm all parameters of the function
Ajax.ActionLink(LinkText, ActionName, new AjaxOptions{onSuccess = "handleUpdate"});
and this seems to be connected with microsoftmvc ajax files that that used to exist in ancient times. You can put alert in each function and check what is the case with you.

Checking if jQuery's $.post() failed due to lost connection

I do a bunch of $.post()'s in my script, within a $(document).ready(function(){
jQuery says:
If a request with jQuery.post() returns an error code, it will fail silently unless the script has also called the global .ajaxError() method.
I tried adding this as a first test
$(document).ajaxError(function(e, xhr, settings, exception) {
alert('error in: ' + settings.url + ' \\n'+'error:\\n' + exception);
});
But it failed to do anything. Can anyone assist? I just need to popup an alert if the internet connection is lost. I also tried using window.navigator.onLine for this but it's not supported in Safari
have you tried not binding it to document?
$('.log').ajaxError(function(e, xhr, settings, exception) {
alert('error in: ' + settings.url + ' \\n'+'error:\\n' + exception);
});
woops, looks like i managed to loose my association with the original post - i made this post.
Anyway to clarify, the code I have is:
$(document).ready(function(){
$(this).ajaxError(function(e, xhr, settings, exception) {
alert('error in: ' + settings.url + ' \\n'+'error:\\n' + exception);
});
$.post("dostuf.php", { action: "thething" });
No error is being thrown.
Not sure on .post(); but in the api for .ajax() there is an error function you can pass to the object.
$.ajax({
type:"post",
url:"http://yourwebservice.com/get_data",
error:function(XMLHttpRequest, textStatus, errorThrown) {
//do stuff
alert('fail whale');
},
success:function(data) {
alert('it worked!');
}
});
See http://api.jquery.com/jQuery.ajax/
By the way, welcome to stackoverflow!

Resources