is there any difference between those AJAX methods? - ajax

I have two questions about jQuery AJAX.
1) Is there any difference between $.load() and $.ajax() used with type: 'GET'? They seem to do the same job.
2) This question is related to the code below. What happens, if I don't write the "type: GET" line at all? Does it mean the same thing?
$(document).ready(function() {
$('#update').click(function() {
$.ajax({
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
success: function(html, textStatus) {
$('body').append(html);
},
error: function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + ( errorThrown ? errorThrown :
391
xhr.status );
}
});
});
});
Is it any different from
$(document).ready(function() {
$('#update').click(function() {
$.ajax({
url: 'hello-ajax.html',
dataType: 'html',
success: function(html, textStatus) {
$('body').append(html);
},
error: function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + ( errorThrown ? errorThrown :
391
xhr.status );
}
});
});
});

This is straight from jQuery Docs (http://api.jquery.com/load/)
The .load() method, unlike $.get(), allows us to specify a portion of
the remote document to be inserted. This is achieved with a special
syntax for the url parameter. If one or more space characters are
included in the string, the portion of the string following the first
space is assumed to be a jQuery selector that determines the content
to be loaded.
Since $.get() is simply the $.ajax() shorthand for "data: 'Get'", it would appear the only major difference is the ability to do the aforementioned (import partial sections of a document).
Edit: To answer your second question, GET is the default data type for the $.ajax() call, POST being your other option. You can read a bit about POST here (http://api.jquery.com/jQuery.post/)

Extracted from jQuery manual .load
This method is the simplest way to fetch data from the server. It is
roughly equivalent to $.get(url, data, success) except that it is a
method rather than global function and it has an implicit callback
function. When a successful response is detected (i.e. when textStatus
is "success" or "notmodified"), .load() sets the HTML contents of the
matched element to the returned data. This means that most uses of the
method can be quite simple:
$( "#result" ).load( "ajax/test.html" );
If no element is matched by the selector — in this case, if the
document does not contain an element with id="result" — the Ajax
request will not be sent.

I guess the difference is that .load() function allows to target the result into a DOM element. Like so
$( "#target" ).load( "source.html" );
And the ajax() method returns an object (eg. JSON) that can be the manipulated. etc. apart from more attributes.

Related

how to specify a different function for each statement in JQuery .always() function

According to the official JQuery documentation:
jqXHR.always(function(data|jqXHR, textStatus, jqXHR|errorThrown) { });
An alternative construct to the complete callback option, the
.always() method replaces the deprecated .complete()method.
In response to a successful request, the function's arguments are the
same as those of .done(): data, textStatus, and the jqXHR object. For
failed requests the arguments are the same as those of .fail(): the
jqXHR object, textStatus, and errorThrown. Refer to deferred.always()
for implementation details.
And let's say that I have the following ajax script :
$.ajax({
url: 'myPHPScript.php',
type: 'POST',
data: {
param_1: 'value_1',
param_n: 'value_n'…
},
username: 'myLogin',
password: 'myPassword',
beforeSend: function() {
alert('The object was created but not yet initilized');
}
}).done(function(data, textStatus, jqXHR) {
alert('All the request was sent and we received data');
}).fail(function(jqXHR, textStatus, errorThrown) {
alert('Error: the following error was occurred: ' + textStatus + ' Status : ' + jqXHR.Status);
}).always(function() {
// Here is my problem
});
In the .always() function, how can I specify a different function for each statement, I mean when the Deferred is resolved, the always() function gets passed the following params (data, textStatus, jqXHR) however if the deferred is rejected it gets passed (jqXHR, textStatus, errorThrown).
Thanks
The only good solution is not using the arguments in always - if you need code specific to the success/failure of the AJAX call out them in done or fail callbacks. Usually the always callback is a place where you do things such as re-enabling a button, hiding a throbber, etc. All those are things where you do not care about the result of the request.
Besides that, you could check arguments.length for the number of arguments and then access the arguments via arguments[0] etc. But relying on the argument count is a bad idea since it might not be future-proof.

JQGrid: loadComplete NOT firing when datatype: function

If I call a function to load my grid data, loadComplete does not fire. I need to handle this event so I can manually update multiselect checkbox correctly. If I update in gridComplete, I have to click the checkbox twice to uncheck it.
In your previous question you wrote that you use WCF on the server side. In the case you don't need to use datatype as function. Instead of that you can just use the following parameters:
datatype: "json",
ajaxGridOptions: { contentType: "application/json" },
serializeGridData: function (data) {
return JSON.stringify(data);
}
To be sure that JSON.stringify are supported in old web browsers you should include json2.js which you can load from here.
In the old answer you can find more code examples (and download the demo) which shows how you can use WCF with jqGrid.
Now I will answer on your original question: "Why loadComplete does not fire" if you use datatype as function. The short answer is: if you use datatype as function your code is responsible for calling of loadComplete.
If you use datatype as function your code is responsible to some things which jqGrid do typically. So first of all you have to understand what should the datatype function do. An example from the documentation (see here) shows the simplest, but not full, implementation of datatype as function. More full code example looks like the following:
$("#list").jqGrid({
url: "example.php",
mtype: "GET",
datatype: function (postdata, loadDivSelector) {
var ts = this, // cache 'this' to use later in the complete callback
p = this.p; // cache the grid parameters
$.ajax({
url: p.url,
type: p.mtype,
dataType: "json",
contentType: "application/json",
data: JSON.stringify(postdata),
cache: p.mtype.toUpperCase() !== "GET",
beforeSend: function (jqXHR) {
// show the loading div
$($.jgrid.jqID(loadDivSelector)).show();
// if loadBeforeSend defined in the jqGrid call it
if ($.isFunction(p.loadBeforeSend)) {
p.loadBeforeSend.call(ts, jqXHR);
}
},
complete: function () {
// hide the loading div
$($.jgrid.jqID(loadDivSelector)).hide();
},
success: function (data, textStatus, jqXHR) {
ts.addJSONData(data);
// call loadComplete
if ($.isFunction(p.loadComplete)) {
p.loadComplete.call(ts, data);
}
// change datatype to "local" to support
// "loadonce: true" or "treeGrid: true" parameters
if (p.loadonce || p.treeGrid) {
p.datatype = "local";
}
},
error: function (jqXHR, textStatus, errorThrown) {
if ($.isFunction(p.loadError)) {
p.loadError.call(ts, jqXHR, textStatus, errorThrown);
}
});
},
... // other parameters
});
You can see that the code in not so short. In the above example we still not support some jqGrid options like virtual scrolling (scroll: 1 or scroll: true).
Nevertheless I hope that I cleared now why I don't recommend to use datatype as function. If you use it you have to understand many things how jqGrid work internally. You should examine it's source code to be sure that you do all things correctly. If you skip somethings, than your code will works incorrect in some situations or in some combination of jqGrid parameters.
If you look at the code which I included at the beginning of my answer (the usage of ajaxGridOptions and serializeGridData) you will see that the code is very easy. Moreover it works with all other legal combination of jqGrid parameters. For example you can use loadonce: true, loadComplete, loadError or even virtual scrolling (scroll: 1 or scroll: true). All things needed depend on the parameters do jqGrid for you.

help debugging an ajax problem

Anyone have any idea why this isn't working?
$(function(){
console.log('ready');
$.ajax({
dataType : 'jsonp',
jsonp : 'js',
url : 'http://monitor.302br.net/MonitorScoreServlet',
beforeSend : function(jqXHR, settings) {
console.info('in beforeSend');
console.log(jqXHR, settings);
},
error : function(jqXHR, textStatus, errorThrown) {
console.info('in error');
console.log(jqXHR, textStatus, errorThrown);
},
complete : function(jqXHR, textStatus) {
console.info('in complete');
console.log(jqXHR, textStatus);
},
success: function(data, textStatus, jqXHR){
console.info('in success');
console.log(data, textStatus, jqXHR);
}
});
});
This was working till recently. The beforeSend handler never fires, but you can see the ajax call being made in firebug, and if you go to the url, it seems to return acceptably formatted results (the same results as before):
http://monitor.302br.net/MonitorScoreServlet?js=jsonp1298046640938
text/javascript:
(84.3);
If I comment out the url, the beforeSend fires, but of course, there's no url....
Any ideas?
AJAX requests are, by definition, restricted to your current domain. Therefore, you cannot request an external URL from your domain.
Ok, I feel dumb. Here's what I think happened: the server used to be set up to take the js param as a callback function. So a url like:
http://monitor.302br.net/MonitorScoreServlet?js=foo
would result in:
foo(84.1);
Whenever we looked in the browser, we were just looking at:
http://monitor.302br.net/MonitorScoreServlet?js
which resulted in:
(84.1);
I assumed jQuery was doing some magic with that to turn it into usable data, but now I think that jQuery was creating something like:
function jsonp1298047240882(data) {
// do something with data
}
So when we changed our back-end code not to create the callback function call, the whole thing stopped working. (It's still weird that the beforeSend handler never gets called, though.)

jQuery AJAX response always returns nothing

The following code returns a blank response no matter whether or not the Function exists, or even the Web Service file entirely:
$.ajax({
url: "/ws.asmx/HelloWorld"
, type: "POST"
, contentType: 'application/json; charset=utf-8'
, data: '{ FileName: "' + filename + '" }'
, dataType: 'json'
, success: function (data) {
}
});
Why is this?
Also, might be worth noting, $.load() works fine!
Your error is that you try to construct JSON data manually and do this in the wrong way:
'{ FileName: "' + filename + '" }'
You should fix the code at least to the following
'{ "FileName": "' + filename + '" }'
because correspond to the JSON specification the property names must be also double quoted.
Next problem can you has if the filename has some special characters. For example, in case of
var filename = '"C:\\Program Files"'; // the '\' must be escaped in the string literal
you should has as the data the corresponding JSON string
'{ "FileName": "\\"C:\\\\Program Files\\"" }'
as the corresponding JSON data because of '\' and '"' must be escaped. It looks dificult. So I stricly recommend you to construct JSON strings with respect of JSON.stringify function from the json2.js. Then the code will be
$.ajax({
type: "POST",
url: "ws.asmx/HelloWorld",
data: JSON.stringify({ FileName: filename }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert(data.d);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("Error Occured!" + " | " + XMLHttpRequest.responseText +
" | " + textStatus + " | " + errorThrown);
}
});
which is simple and clear enough. The next advantage of the usage JSON.stringify is that the most modern web browsers has native support of the function and the function work very quickly.
By the way in case of the usage of JSON.stringify you can easy call web service methd having very complex data structures (classes) as the parameters and not only strings.
UPDATED: One more remrk to reduce possible misunderstanding. It you later deceide to use HTTP GET instead of HTTP POST to call the web method you will have to change the data parameter from
JSON.stringify({ FileName: filename })
to
{ FileName: JSON.stringify(filename) }
UPDATED 2: You can download this Visual Studio 2010 project which I used to test all before I posted my answer. I included as "Web-3.5.config" the web.config for .NET 3.5. All different commented data values included in the default.htm work. If you want make tests with HTTP GET you should uncomment the section in web.config which allows HttpGet and use ScriptMethod having UseHttpGet = true. All the lines are included in the demo as comments.
just to try use:
$.getJSON("/ws.asmx/HelloWorld", function(data){
alert(data);
});
Check if you get the data back.
Use AJAX-Enabled Web Service
Make sure you have loaded the jquery.js file properly.
Does the service return a value? If not, it will just POST and not give you back anything, because there is no data to see...
If you want to watch for errors, you can add an error callback
$.ajax({
url: "/ws.asmx/HelloWorld"
, type: "POST"
, contentType: 'application/json; charset=utf-8'
, data: '{ FileName: "' + filename + '" }'
, dataType: 'json'
, success: function (data) {
}
, error: function (a, b, c) {
}
});
From jQuery:
error(jqXHR, textStatus, errorThrown)Function
A function to be called if the request fails. The function receives
three arguments: The jqXHR (in jQuery
1.4.x, XMLHttpRequest) object, a string describing the type of error
that occurred and an optional
exception object, if one occurred.
Possible values for the second
argument (besides null) are "timeout",
"error", "abort", and "parsererror".
This is an Ajax Event. As of jQuery
1.5, the error setting can accept an array of functions. Each function will
be called in turn. Note: This handler
is not called for cross-domain script
and JSONP requests.
I read somewhere that the contentType header for POST must be:
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
and I use it blindly: it's always worked.
-- pete

MVC2 One Async Call, Multiple Async Updates

I have an operation on my Page that then requires 3 long (few seconds each) operations to be performed in series. After each operation is performed though, I would like the controller to return a partial view and have the page update with a status (keeps the user informed, I find that if people know that stuff is happening they worry less). Is there a MVC 'way' of doing this, or should I just use jQuery to do it?
Thanks.
You will want to use jQuery to issue three separate calls to three separate control methods and update the three areas of the page upon return separately.
The only way to "bunch" up calls would be to combine it all into one, but you can't get return values fired back to the client upon return of more than one call (almost like streaming, there's nothing listening on the client end after you return your first result set, that connection is closed).
So I have created a slight hack, that seems to work:
On the client side I have:
function onClickHandler() {
updateUI("Beginning Batch...");
setTimeout(klugeyClick, 0);
}
function klugeyClick() {
$.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action1", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action1 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
setTimeout(klugeyClick2, 0);
}
function klugeyClick2() {
$.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action2", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action2 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
setTimeout(klugeyClick3, 0);
}
function klugeyClick3() {
$.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action3", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action3 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
}
function updateUI(result) {
$("#UIelement").text(result);
}
On the server side I have:
Function Action1() As JsonResult
System.Threading.Thread.Sleep(3000)
Return Json("Operation One Complete...")
End Function
Function Action2() As JsonResult
System.Threading.Thread.Sleep(3000)
Return Json("Operation Two Complete...")
End Function
Function Action3() As JsonResult
System.Threading.Thread.Sleep(3000)
Return Json("Operation Three Complete...")
End Function
Now I have two problems. First, I would like to have a follow up message that displays "Batch Complete" but following the same pattern and just adding another 'klugeyClick' with a call to UpdateUI (with or without a seTimeout) causes the last operation message not to be displayed. I think the callback within the jQuery.ajax method makes this kluge work somehow but without an ajax call, I can't put any follow-up messages.
The next problem is that although all my calls are getting to my webservice and are returning json results just fine, I always get an error coming back from the jQuery callback. Any ideas why this might be?
Thanks.
So as far as I can tell, the only way to get a Follow up message to appear the way I want it do (i.e. a few seconds after my last operation) is to have a dummy webservice method that I call that returns the last message after a delay... crumby.
Now my last problem is that all of my calls to my jsonResult actions come back with a textStatus of 'error' to the client. Now according to the docs this means an http error, but how could there be an http error if the method was called on the server side correctly and a Json result was produced (verified by setting a breakpoint on the server)?
For our site we have a big action that requires some time. That action is composed by subactions, we aggregate the results and we build a nice view.
One year ago:
We were doing that in a sequence: action1, then action2, etc.
We had that typical page of: please wait.
Tricks that can help you:
We do parallel requests on the server side.
We wait for results in a results page. The javascript there needs some time to load, so while the server searches, we load the page.
We ask the server every second: have you finished? And we get partial results as the different actions complete.
I don't know if you can apply all of these things to your problem but some of then can be really nice.
We don't use MVC, we use some asmx services with jQuery and ajax.
The reason your "kludgy" solution works is because the setTimeout() method creates an event. Thus your logic is:
Update UI
Setup event for step 1:
Start "ajax" call
Wait for "ajax" to finish
Setup event for step 2
Start "ajax" call
Wait for "ajax" to finish
Setup event for step 3
Start "ajax" call
This is precisely what the callback feature of ajax() is for.
function Step1() {
$.ajax({
type: "GET",
dataType: "json",
url: "/ControllerName/Action1",
success: function(msg) {
updateUI(msg);
Step2(); // call step 2 here!
},
async: true, // don't block the UI
error: function(XMLHttpRequest, textStatus, errorThrown) {
updateUI("Action1 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown);
}
});
}
function Step2() {
// similar to step one
}

Resources