ajaxchain.md 5.12 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
# $.ajaxchain

Chains AJAX requests. [$.ajax][ajax] fetches a single page, like this:

```js
$.ajax({
  url: 'formhandler',       // Fetch "formhandler" URL
  data: {_offset: 0}        //    with ?_offset=0
})
```

`$.ajaxchain` keeps fetching more page using a `chain:` function.

```js
var ajaxchain_instance = $.ajaxchain({
  url: 'formhandler',                           // Fetch "formhandler" URL
  data: {_offset: 0, _limit: 10},               //    with ?_offset=0&_limit=10
  chain: function(response, request) {          // When the response is retrieved
    if (response.length > 0)                    //    if the response is non-empty
      return {data: {_offset: request.data._offset + 10}    //    fetch the next page
  },
  limit: 10,                                    // Get at most 10 pages (default)
  // any other $.ajax options can be passed
})
```

The flow when `$.ajaxchain(request)` is called is:

1. Fetch URL using [$.ajax][ajax] using the request options
2. If the page limit is not reached, call the `.chain(response, request, xhr)` function.
  - `request` is the request sent to [$.ajax][ajax]
  - `response` is the response from [$.ajax][ajax]
  - `xhr` is the [jqXHR][jqxhr] object
3. If `.chain()` returns a non-empty object
  - update the `request` with the response of `.chain()`
  - call `$.ajaxchain(request)` with the new request
  - Otherwise, stop.

## $.ajaxchain options

`$.ajaxchain()` accepts the same options as [$.ajax][ajax] with a few additional options:

- `chain`: a function that returns updates to the request object
- `limit`: the maximum number of pages to fetch

The `chain:` function can be used with [FormHandler](https://learn.gramener.com/guide/formhandler/).

```js
  chain: function(response, request) {
    if (response.length > 0)                              // If the response is not empty
      return {data: {_offset: request.data._offset + 10}}   // Fetch the next page
  }
```

You can use a set of pre-defined helper functions for chaining:

- `chain: $.ajaxchain.list()` chains a list of URLs.
    - `chain: $.ajaxchain.list([url1, url2, url3])` fetches `url1`, `url2` and `url3` one after another
- `chain: $.ajaxchain.cursor(target, source)` uses a page cursor or token to identify the next page
    - Requires [lodash](https://lodash.com/)
    - The `source` is the [object path](https://lodash.com/docs/#get) from the
      response that has the next cursor value. For example: `a.b` means `response.a.b`
    - The `target` is the update to be made to the `request`. For example,
      `data.token` sets `?token=`. `headers.X-Token` sets the `X-Token` header.
    - Google APIs like [YouTube PlaylistItems](https://developers.google.com/youtube/v3/docs/playlistItems/list)
      can use `chain: $.ajaxchain.cursor('data.pageToken', 'nextPageToken')`.
      It fetches the next URL with `?pageToken=` as the `nextPageToken` key from the response.
    - [Twitter APIs](https://developer.twitter.com/en/docs/ads/general/guides/pagination.html)
      can use `chain: $.ajaxchain.cursor('data.cursor', 'next_cursor')`
    - [Facebook APIs](https://developers.facebook.com/docs/graph-api/using-graph-api/#paging)
      can use `chain: $.ajaxchain.cursor('url', 'paging.next')`

You can also construct your own `chain:` functions. For example:

On [YouTube](https://developers.google.com/youtube/v3/docs/playlistItems/list):

```js
  chain: function(response, request) {
    if (response.nextPageToken)
      return {data: {pageToken: response.textPageToken}}
  }
```

If the results are at `/page/1`, `/page/2`, etc:

```js
  url: `/page/1`,
  chain: function(response, request) {
    if (response.length > 0)
      return {url: `/page/` + (+request.url.split('/')[-1] + 1)}
  }
```

## $.ajaxchain events

To access the response, we can use the `ajaxchain_instance` events. There are 3 events:

- `done` is fired when ALL pages have been loaded. Event attributes are:
    - `response`: list of responses returned by each [$.ajax][ajax] request
    - `request`: list of requests passed to each [$.ajax][ajax]
- `load` is fired when each page is loaded. Event attributes are:
    - `request`: the parameters passed to [$.ajax][ajax] request
    - `response`: data returned by [$.ajax][ajax] request
    - `xhr`: the [jqXHR][jqxhr] object
- `error` is fired when there is an error. Event attributes are:
    - `request`: the parameters passed to [$.ajax][ajax] request that failed
    - `xhr`: the [jqXHR][jqxhr] object that failed
    - `exception`: any exception thrown when calling the `chain` function

For example:

```js
ajaxchain_instance
  .on('done', function(e) {           // Called after ALL pages are loaded, or on error
    // Responses are in e.response[0], e.response[1], etc
    // Requests  are in e.request[0],  e.request[1],  etc
  })
  .on('load', function(e) {           // Called when each page is loaded
    // e.response has the response
    // e.request  has the request
  })
  .on('error', function(e) {          // Called when there's an error
    // e.request  has the request
    // e.exception is set if the .change() function threw an exception
  })
```

[ajax]: http://api.jquery.com/jQuery.ajax/
[jqxhr]: http://api.jquery.com/Types/#jqXHR