One method behind them all
$.get(), $.getJSON() and $.post() are shortcuts. They all call $.ajax(), which takes one object of options and can make any HTTP request:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$.ajax({
url: "https://jsonplaceholder.typicode.com/users/2",
method: "GET",
dataType: "json"
})
.done(function (user, textStatus, jqXHR) {
console.log("done:", user.name, "|", textStatus, "|", jqXHR.status);
})
.fail(function (jqXHR, textStatus, errorThrown) {
console.log("fail:", jqXHR.status, textStatus, errorThrown);
})
.always(function () {
console.log("always: the request has finished");
});
</script>done: Ervin Howell | success | 200
always: the request has finishedThe jqXHR object
$.ajax() returns a jqXHR object straight away, before the response arrives. You attach handlers to it:
.done(fn)runs on success with(data, textStatus, jqXHR)..fail(fn)runs on failure with(jqXHR, textStatus, errorThrown)..always(fn)runs after either, which makes it the right place to hide a spinner or re-enable a button..then(success, failure)works too, and jqXHR can be used withawait(Deferreds lesson).
Older code passes success:, error: and complete: functions inside the options object. They do the same job; the chained style is easier to read and lets you add handlers later, for example in a different function that receives the jqXHR.
The most useful options
| Option | Meaning |
|---|---|
url |
where to send the request |
method |
"GET" (default), "POST", "PUT", "PATCH", "DELETE" (type is the old name) |
data |
values to send: an object, a string, or (with processData: false) FormData |
dataType |
what you expect back: "json", "html", "text", "script" |
contentType |
the format of what you send, e.g. "application/json" |
headers |
extra request headers, such as an auth or CSRF token |
timeout |
give up after this many milliseconds |
cache |
false adds a timestamp parameter so browsers do not reuse an old GET response |
Reading response details
The jqXHR object also exposes the HTTP status and headers:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$.ajax({ url: "https://jsonplaceholder.typicode.com/posts", data: { userId: 1 } })
.done(function (posts, status, xhr) {
console.log("status:", xhr.status);
console.log("content type:", xhr.getResponseHeader("Content-Type"));
console.log("posts:", posts.length, "| parsed automatically:", Array.isArray(posts));
});
</script>status: 200
content type: application/json; charset=utf-8
posts: 10 | parsed automatically: trueWithout dataType, jQuery parses the response according to its Content-Type; this API sends application/json, so posts arrived as an array.
Handling a failure
The server may answer with an error status. With $.ajax(), any status outside 200 to 299 (and 304) goes to .fail():
<p id="msg"></p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$.ajax({ url: "https://jsonplaceholder.typicode.com/posts/99999", dataType: "json" })
.done(post => console.log("found", post.id))
.fail(function (xhr, textStatus) {
$("#msg").text(xhr.status === 404 ? "That post does not exist." : "Something went wrong.");
console.log("failed with", xhr.status, "|", textStatus);
});
</script>failed with 404 | errorThe next lessons cover sending data and handling every kind of failure, including timeouts and lost connections.
Defaults for every request
$.ajaxSetup(options) sets defaults used by every later request. The most common real use is sending a CSRF token with every request in frameworks like Laravel, which put it in a meta tag:
$.ajaxSetup({
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") }
});Use $.ajaxSetup() only for settings that truly apply everywhere. Defaults that change the behaviour of all requests, such as a global dataType or timeout, surprise anyone reading a single $.ajax() call (and break plugins that make their own requests). Prefer a small wrapper function of your own:
function api(path, options) {
return $.ajax($.extend({ url: "/api" + path, dataType: "json", timeout: 10000 }, options));
}
api("/products").done(render);Global Ajax events
jQuery fires events on document for every request: ajaxStart (the first request begins), ajaxStop (all requests have finished), plus ajaxSend, ajaxSuccess, ajaxError and ajaxComplete. A page-wide "loading" indicator can use them:
$(document)
.on("ajaxStart", () => $("#busy").show())
.on("ajaxStop", () => $("#busy").hide());Pass global: false in a request's options to keep it out of these events.
Common mistakes
- Expecting
$.ajax()to return the data. It returns jqXHR; the data arrives in.done(). - Using
dataTypeto send JSON. It only describes the response. - Forgetting
.fail(), so errors leave the page stuck on "Loading...". - Putting clean-up only in
.done(), so a failed request never re-enables the button. Use.always().
Exercise
Use $.ajax() to load https://jsonplaceholder.typicode.com/todos/5. On success, log done: with the to-do's title; on failure, log failed: with the status; and in .always(), log finished.
Show one possible answer
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$.ajax({ url: "https://jsonplaceholder.typicode.com/todos/5", dataType: "json" })
.done(task => console.log("done:", task.title))
.fail(xhr => console.log("failed:", xhr.status))
.always(() => console.log("finished"));
</script>done: laboriosam mollitia et enim quasi adipisci quia provident illum
finishedKey points
- $.ajax({ url, method, data, dataType, headers, timeout }) is the full-featured request method; the shortcuts all call it.
- It returns a jqXHR object; attach .done() for success, .fail() for errors and .always() for code that runs either way.
- dataType says what you expect back ("json", "html", "text"); method sets GET, POST, PUT, PATCH or DELETE.
- $.ajaxSetup() sets defaults for every request, such as a CSRF header, but use it sparingly.