Taking full control of an Ajax request

The functions and methods you’ve seen so far are convenient for many cases, but there may be times when you want to take control of all the nitty-gritty details into your own hands. For example, you may want to be sure that each time your Ajax request is performed, you’ll receive fresh data (that is, avoid the browser cache). Another situation where the use of a lower-level method may come in handy is when you need to perform an Ajax request but its result is important only if retrieved within a certain amount of time. The last example we want to mention is that sometimes you could receive the result of the Ajax call in a certain format—for example, as plain text—but you prefer it to be converted into another one, such as HTML or XML.

In this section, we’ll explore how jQuery lets you exert such dominion.

Making Ajax requests with all the trimmings

For those times when you want or need to exert fine-grained control over how you make Ajax requests, jQuery provides a general utility function for making Ajax requests: $.ajax(). Under the covers, all other jQuery features that make Ajax requests eventually use this function to perform the request. Its syntax is as follows.

Function syntax: $.ajax
$.ajax(url[, options])
$.ajax([options])
Performs an Ajax request using the URL and the options passed to control how the request is made and callbacks notified. In the second version of this utility function, the URL is specified in the options. If no parameters are specified, the request is made to the current page.
Parameters
url(String) The string containing the URL to which the request is sent.
options(Object) An object whose properties define the parameters for this operation. See table 10.2 for details.
Returns
The jqXHR instance.

Looks simple, doesn’t it? But don’t be deceived. The options parameter can specify a very large range of values that can be used to tune the operation of this function, including the URL to which to send the request. These options (in general order of their importance and the likelihood of their use) are defined in table 10.2.

Table 10.2. Options for the $.ajax() utility function
NameDescription
url(String) The string containing the URL to which the request is sent. If an empty string is passed, the request is sent to the current URL at the time the method is invoked.
method(String) The HTTP method to use. Usually either POST or GET. If omitted, the default is GET. If you’re using versions of jQuery prior to 1.9.0, this same property must be named as type instead.
data(String|Object|Array) Defines the values that will be sent to the server. If the request is a GET, the values are passed as the query string. If a POST, the values are passed as the request body. In either case, the encoding of the values is handled by the $.ajax() utility function. This parameter can be a string that will be used as the query string or response body, an object whose properties are serialized, or an array of objects whose name and value properties specify the name/value pairs.
dataType(String) In its basic form, it’s a keyword that identifies the type of data that’s expected to be returned by the response. This value determines what, if any, postprocessing occurs upon the data before being passed to callback functions. The valid values are as follows:xml —The response text is parsed as an XML document and the resulting XML DOM is passed to the callbacks.html —The response text is passed unprocessed to the callback functions. Any <script> blocks within the returned HTML fragment are evaluated.json —The response text is evaluated as a JSON string and the resulting object is passed to the callbacks.jsonp —Similar to json except that remote scripting is allowed, assuming the remote server supports it.script —The response text is passed to the callbacks. Prior to any callbacks being invoked, the response is processed as a JavaScript statement or statements.text —The response text is assumed to be plain text.The server is responsible for setting the appropriate content-type response header. The default value is determined by jQuery depending on the response obtained and will be one among xml, json, script, or html. The value of this option can also be a string of space-separated values. In this case, jQuery converts a data type into another. For example, if the response is text and you want it to be treated as XML, you can write “text xml”.
cache(Boolean) If false, ensures that the response won’t be cached by the browser. Note that this works correctly only with HEAD and GET requests. Defaults to true except when dataType is specified as either script or jsonp.
context(Object|Element) Specifies an object or DOM element that is to be set as the context of all callbacks related to this request. By default, the context is an object that represents the Ajax settings used in the call.
timeout(Number) Sets a timeout for the Ajax request in milliseconds. The timeout period starts at the point the $.ajax() call is made. If the request doesn’t complete before the timeout expires, the request is aborted and the error callback (if defined) is called.
global(Boolean) If false, disables the triggering of global Ajax events. These are jQuery-specific custom events that trigger at various points or conditions during the processing of an Ajax request. We’ll discuss them in detail in an upcoming section. If omitted, the default (true) is to enable the triggering of global events.
contentType(String) The content type to be specified on the request. If omitted, the default is application/x-www-form-urlencoded; charset=UTF-8, the same type used as the default for form submissions.
success(Function|Array) A function or an array of functions invoked if the response to the request indicates a success status code. The response body is returned as the first parameter to this function and evaluated according to the specification of the dataType property. The second parameter is a string containing a status value—in this case, always the string “success”. A third parameter provides a reference to the jqXHR instance.
error(Function|Array) A function or an array of functions invoked if the response to the request returns an error status code. Three arguments are passed to this function: the jqXHR instance, a status message string (in this case, one of “error”, “timeout”, “abort”, or “parseerror”), and an optional exception object, sometimes returned from the jqXHR instance, if any. This handler is not called for cross-domain script and cross-domain JSONP requests.
complete(Function|Array) A function or an array of functions called upon completion of the request. Two arguments are passed: the jqXHR instance and a status message string of “success”, “error”, “notmodified”, “timeout”, “abort”, or “parseerror”. If either a success or error callback is also specified, this function is invoked after that callback is called.
beforeSend(Function) A function invoked prior to initiating the request. This function is passed the jqXHR instance and can be used to set custom headers or to perform other prerequest operations. Returning false from this handler will cancel the request.
async(Boolean) If specified as false, the request is submitted as a synchronous request. By default, the value is true and the request is asynchronous. Cross-domain requests and dataType: “jsonp” requests do not support synchronous operation.
processData(Boolean) If set to false, prevents the data passed from being processed into URL-encoded format. By default, the value is true and the value of data is URL-encoded into a format suitable for use with requests of type application/x-www-form-urlencoded.
contents(Object) An object of string/regular-expression pairs that determine how jQuery will parse the response, given its content type.
converters(Object) An object containing dataType-to-dataType converters. Each converter’s value is a function that returns the transformed value of the response.
crossDomain(Boolean) Set it to true to force a crossDomain request on the same domain. By default, its value is false for same-domain requests and true for cross-domain requests.
headers(Object) An object of additional header key/value pairs to send along with requests. By default, its value is an empty object.
dataFilter(Function) A callback invoked to filter the response data. This function is passed the raw response data and the dataType value and is expected to return the “sanitized” data.
ifModified(Boolean) If true, allows a request to succeed only if the response content has not changed since the last request, according to the Last-Modified header. If omitted, no header check is performed. Defaults to false.
isLocal(Boolean) Allow the current environment to be recognized as local (for example, the filesystem). The protocols that jQuery recognizes as local by default are file, *-extension, and widget.
jsonp(String) Specifies a query parameter name to override the default jsonp callback parameter name of callback.
jsonpCallback(String|Function) Specifies the callback function name for a JSONP request. This value will be used instead of the random name automatically generated by jQuery.
username(String) The username to be used in the event of an HTTP authentication request.
password(String) The password to be used in the case of an HTTP authentication request.
scriptCharset(String) The character set to be used for script and jsonp requests when the remote and local content are of different character sets.
statusCode(Object) An object containing a set of numeric HTTP codes and functions to be called when the response has the corresponding code. By default, its value is an empty object.
xhr(Function) A callback used to provide a custom implementation of the XHR instance.
xhrFields(Object) An object of name-value pairs to set on the native XHR object. By default, the object is empty.
accepts(Object) The content type sent in the request header that tells the server what kind of response it will accept in return. By default, its value depends on dataType.
mimeType(String) A mime type to override the XHR mime type.
traditional(Boolean) If true, the traditional style of parameter serialization is used. See the description of $.param() in lesson 9 for details on parameter serialization.

Don’t be scared by this list. We know it can be a bit overwhelming, but first of all, you don’t have to remember all these options (this app and the official documentation serve this purpose), and second, it’s unlikely that more than a few of them will be used for any one request.

What’s JSONP all about?

JSON is a lightweight and heavily used data-interchange format. Websites usually retrieve data in such a format by performing Ajax requests using an XHR object. This mechanism abides by the same-origin policy, which dictates that certain types of data transfer must be restricted to only occur if the target resource’s domain is identical to the page making the request. To bypass this limit, a new mechanism called JSONP was proposed in December 2005 by Bob Ippolito in his article “Remote JSON – JSONP”.

JSONP (an abbreviation of “JSON with padding”) works by creating a script element (either in HTML markup or inserted into the DOM via JavaScript), with a reference to a resource that returns JSON data that’s wrapped by a function declared on the page performing the request, whose name is provided by the script element. Usually the name of the function is passed using a parameter named callback. For example, you might create the following script element:

<script src="http://www.example.com/data?callback=myFunction"></script>

In this case, myFunction() is a function defined in the page that performs the request that has to deal with the JSON returned. A server able to deal with such requests will usually respond as shown here:

myFunction({"name": "jQuery in Action"});

This causes the myFunction() function to be executed with the data returned by the server passed as an argument.

To learn more about JSONP.

“No examples to use $.ajax()?” we hear you say. Don’t worry; the next lesson will be dedicated to creating an Ajax-powered project.

Sometimes it might be convenient if you could set default values for the options presented in table 10.2 for pages where you’re planning to make a large number of requests. Let’s discover how you can do that.

Setting request defaults

jQuery provides a way for you to define a default set of Ajax properties that will be used when you don’t override their values. This can make pages that initiate lots of similar Ajax calls much simpler. The function to set up the list of Ajax defaults is $.ajaxSetup().

Method syntax: $.ajaxSetup
$.ajaxSetup(options)
Establishes the passed set of option properties as the defaults for subsequent calls to $.ajax() or its derived methods like $.get() and $.post(), including those performed by third-party libraries or plugins.
Parameters
options(Object) An object instance whose properties define the set of default Ajax options. These are the same properties described for the $.ajax() function in table 10.2. This function shouldn’t be used to set callback handlers for success, error, and completion. (You’ll see how to set these up using an alternative means in an upcoming section.)
Returns
undefined

At any point in script processing this function can be used to set up defaults to be used for all subsequent calls to $.ajax(). This method has to be used carefully because it’ll also change the way plugins and other libraries you’re using on your web pages perform Ajax calls using $.ajax() and similar methods.

Note

Defaults set with this function aren’t applied to the load() method. Also, for utility functions such as $.get() and $.post(), the HTTP method can’t be overridden by these defaults. For example, setting a default type of "GET" won’t cause $.post() to use the GET HTTP method.

Let’s say that you’re setting up a page where, for the majority of Ajax requests (made with the utility functions rather than the load() method), you want to set up some defaults so that you don’t need to specify them on every call. You can write the following as the first statement in the script element:

$.ajaxSetup({
  type: 'POST',
  timeout: 5000,
  dataType: 'html'
});

This would ensure that every subsequent Ajax call (except as noted previously) would use these defaults, unless explicitly overridden in the properties passed to the Ajax utility function being used. Specifically you’re setting that all the requests will be POST requests, that the maximum time after which the request has to time out is 5 seconds (5000 milliseconds), and that the response expected has to be interpreted as HTML.

Now, what about those global events we mentioned that were controlled by the global option?

Handling Ajax events

Throughout the execution of Ajax requests, jQuery triggers a series of custom events for which you can establish handlers in order to be informed of the progress of a request or to take action at various points along the way. jQuery classifies these events as local events and global events.

Local events are handled by the callback functions that you can directly specify using the beforeSendsuccesserror, and complete options of the $.ajax() function or indirectly by providing callbacks to the convenience methods (which, in turn, use the $.ajax() function to make the actual requests). You’ve been handling local events all along, without even knowing it, whenever you’ve registered a callback function to any jQuery Ajax function.

Global events are triggered for any Ajax request on the web page. You can establish event handlers for them via the on() method (just like any other event) used on document (attaching them on any other element won’t work). The global events, many of which mirror local events, are ajaxStartajaxSendajaxSuccessajax-ErrorajaxStop, and ajaxComplete.

The attached handlers receive three parameters: the jQuery.Event instance, the jqXHR instance, and the object containing the options passed to $.ajax(). Exceptions to this parameter list are noted in table 10.3, which shows the jQuery Ajax events in the order in which they’re delivered.

Table 10.3. jQuery Ajax event types
Event nameTypeDescription
ajaxStartGlobalTriggered when an Ajax request is started, as long as no other requests are active. For concurrent requests, this event is triggered only for the first of the requests. Only the jQuery.Event instance is passed.
beforeSendLocalInvoked prior to sending the request in order to allow modification of the XHR instance. You can cancel the request by returning false.
ajaxSendGlobalTriggered prior to sending the request in order to allow modification of the XHR instance.
successLocalInvoked when a request returns a successful response.
ajaxSuccessGlobalTriggered when a request returns a successful response.
errorLocalInvoked when a request returns an error response.
ajaxErrorGlobalTriggered when a request returns an error response. An optional fourth parameter referencing the thrown error, if any, is passed.
completeLocalInvoked when a request completes, regardless of its status. This callback is invoked even for synchronous requests.
ajaxCompleteGlobalTriggered when a request completes, regardless of its status. This callback is invoked even for synchronous requests.
ajaxStopGlobalTriggered when an Ajax request completes and there are no other concurrent requests active. Only the jQuery.Event instance is passed.

To make sure things are clear, we want to stress that local events represent callbacks passed to $.ajax() (and its shortcuts), whereas global events are custom events that are triggered and can be handled by established handlers (to document), just like other event types.

In table 10.3 we reported that ajaxStart and ajaxStop receive a jQuery.Event instance as their only parameter. This parameter doesn’t have a real use case, so it isn’t reported in the official documentation. But we still wanted to report it for the sake of precision (and because we’ll use it in the next demo). You can read more about this topic at https://github.com/jquery/api.jquery.com/issues/478.

In addition to using on() to establish event handlers, jQuery provides a handful of convenience functions to establish the handlers, as follows.

Method syntax: jQuery Ajax event establishers
ajaxComplete(callback)
ajaxError(callback)
ajaxSend(callback)
ajaxStart(callback)
ajaxStop(callback)
ajaxSuccess(callback)
Establishes the passed callback as an event handler for the jQuery Ajax event specified by the method name.
Parameters
callback(Function) The function to be established as the Ajax event handler. The function context (this) is the DOM element upon which the handler is established. Parameters may be passed as outlined in table 10.3.
Returns
The jQuery collection.

Let’s put together a simple example of how some of these methods can be used to easily track the progress of Ajax requests. The layout of our test page (it’s too simple to be called a lab) is shown in figure 10.9 and is available at http://localhost[:8080]/lesson-10/ajax.events.html.

Figure 10.9. The initial display of the page we’ll use to examine the jQuery Ajax events by firing multiple events and observing the handlers

This page exhibits three controls: a count field, a Good request button, and a Bad request button. These buttons are instrumented to issue the number of requests specified by the count field. The Good request button will issue requests for a valid resource, whereas the Bad request button will issue the same number of requests for an invalid resource that will result in failures.

In the code of this page, you define a number of event handlers as follows:

var $log = $('#log');
$(document).on(
   'ajaxStart ajaxStop ajaxSend ajaxSuccess ajaxError ajaxComplete',
   function(event) {
      $log.text($log.text() + event.type + '\n');
   }
);

This statement establishes a handler on the document object for each of the various jQuery Ajax event types. The handler writes a message showing the event type that was triggered into a textarea element having log as its ID.

Leaving the request count at 1, click the Good request button and observe the results. You’ll see that each jQuery Ajax event type is triggered in the order described in table 10.3. But to understand the distinctive behavior of the ajaxStart and ajaxStop events, set the count control to 2 and click the Good request button. You’ll see the display shown in figure 10.10.

Figure 10.10. When multiple requests are active, the ajaxStart and ajaxStop events are called around the set of requests rather than for each.

Here you can see how, when multiple requests are active, the ajaxStart and ajaxStop events are triggered only once for the entire set of concurrent requests, whereas the other event types are triggered on a per-request basis.

Now try clicking the Bad request button to generate an invalid request and observe the event behavior. You’ll obtain the result shown in figure 10.11, which proves that this time the ajaxError event is fired.

Figure 10.11. The result of a bad request shows that the ajaxError event is called.

As you’ve seen, $.ajax() gives you a lot of options to use, offering you great flexibility, but there may be times (not a lot, to be honest) when you want to do even more. For instance, you may want to handle requests based on some options or modifying existing ones before a request is made or to manage the transfer of the data of an Ajax call. A possible use case, as we’ll discuss in the next section with an example, is to prevent an Ajax call to some domains you want to deny access to. Let’s see what jQuery has to offer for such situations.

Advanced Ajax utility functions

In addition to all the methods and utility functions we’ve discussed so far, jQuery has other goodies to offer. Probably you won’t have a lot of chances to see these two utility functions in action, but because they exist, we want to introduce you to them. Say “Hi!” to $.ajaxPrefilter() and $.ajaxTransport().

$.ajaxPrefilter() can be used to prevent an Ajax request based on some custom options you set when you called $.ajax(). Its syntax is reported here.

Method syntax: $.ajaxPrefilter
$.ajaxPrefilter([dataTypes,] callback)
Handles custom Ajax options or modifies existing options before each request is sent and before they’re processed by subsequent calls to $.ajax().
Parameters
dataTypes(String) An optional string containing one or more space-separated dataTypes as described for the $.ajax() function in table 10.2. If this parameter is passed, the handler is called only if the dataTypes of the request match.
callback(Function) A function to set default values for future Ajax requests. This function receives three parameters: options containing the request options, originalOptions that stores the options provided to the $.ajax() call (without the defaults from ajaxSettings), and jqXHR, which is the jqXHR object of the request.
Returns
undefined

To see a concrete example of its use, imagine that you want to abort all the requests of type XML directed to a certain set of domains. You may want to do so because you know that they’ll always fail.

To achieve this goal you can write code like the following, also available in the file http://localhost:8080/lesson-10/$.ajaxPrefilter.html and as a JS Bin:

The aim of this function isn’t limited to changing the behavior of the Ajax calls based on the options set. It can also be employed in cases where you want to redirect a request from the original dataType to another, which is achieved by returning the dataType you want.

The other less-known function we want to mention is $.ajaxTransport(). This is a low-level function that allows you to take control of how $.ajax() issues the transport of a request’s data. Its syntax is shown here.

Function syntax: $.ajaxTransport
$.ajaxTransport([dataType,] callback)
Creates an object that handles the actual transmission of Ajax data.
Parameters
dataType(String) An optional string containing the data type to use. If this parameter is passed, the handler is called only if the dataType of the request matches.
callback(Function) A function to return the new transport object to use with the dataType provided. This function receives three parameters: options containing the request options, originalOptions that stores the options provided to the $.ajax() call (without the defaults from ajaxSettings), and jqXHR, which is the jqXHR object of the request.
Returns
undefined

The callback function of this method has to return a new transport object, which is a JavaScript object that provides two methods, send() and abort(), that are used internally by $.ajax().

The send() function receives two parameters called headers and completeCallback. The former is an object of key-value pairs of request headers that the transport can transmit if it supports it, whereas the latter is the callback used to notify $.ajax() of the completion of the request.

With this last somewhat complicated utility function, we’ve completed our overview of the methods and functions jQuery provides to deal with Ajax. The examples shown so far are a good start to sink your teeth into jQuery’s way of dealing with Ajax. Nonetheless you, our dear reader, deserve much more than that.

The aim of the next lesson is to show a real-world example that employs the power of Ajax to solve a common problem that you may face—and have probably already faced.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *