Deep linking into DataTables
A question that comes up relatively frequently in the forums is "how do I deep link into a DataTable?" This is usually asked in the context of SEO where you want to ensure that all of the data in the table is indexable, but it can also be appropriate in applications where you want to show a table with a specific search term pre-set.
Typically the answer to such a question is to use the initialisation parameters to set whatever option is required from the search string, but it is such a common thing to want to do, it is sensible that we generalise it. To that end, here I present a short script that can be used to extract parameters from a search string and use them to populate a DataTable.
Let's see it in action first - follow the links below to observe the behaviour on the demonstration table:
- Start at page 2
- Set a search term ("software")
- Set a default order on the second column
- Reset - no options.
Name | Position | Office | Age | Start date | Salary |
---|---|---|---|---|---|
Tiger Nixon | System Architect | Edinburgh | 61 | 2011-04-25 | $320,800 |
Garrett Winters | Accountant | Tokyo | 63 | 2011-07-25 | $170,750 |
Ashton Cox | Junior Technical Author | San Francisco | 66 | 2009-01-12 | $86,000 |
Cedric Kelly | Senior Javascript Developer | Edinburgh | 22 | 2012-03-29 | $433,060 |
Airi Satou | Accountant | Tokyo | 33 | 2008-11-28 | $162,700 |
Brielle Williamson | Integration Specialist | New York | 61 | 2012-12-02 | $372,000 |
Herrod Chandler | Sales Assistant | San Francisco | 59 | 2012-08-06 | $137,500 |
Rhona Davidson | Integration Specialist | Tokyo | 55 | 2010-10-14 | $327,900 |
Colleen Hurst | Javascript Developer | San Francisco | 39 | 2009-09-15 | $205,500 |
Sonya Frost | Software Engineer | Edinburgh | 23 | 2008-12-13 | $103,600 |
Jena Gaines | Office Manager | London | 30 | 2008-12-19 | $90,560 |
Quinn Flynn | Support Lead | Edinburgh | 22 | 2013-03-03 | $342,000 |
Charde Marshall | Regional Director | San Francisco | 36 | 2008-10-16 | $470,600 |
Haley Kennedy | Senior Marketing Designer | London | 43 | 2012-12-18 | $313,500 |
Tatyana Fitzpatrick | Regional Director | London | 19 | 2010-03-17 | $385,750 |
Michael Silva | Marketing Designer | London | 66 | 2012-11-27 | $198,500 |
Paul Byrd | Chief Financial Officer (CFO) | New York | 64 | 2010-06-09 | $725,000 |
Gloria Little | Systems Administrator | New York | 59 | 2009-04-10 | $237,500 |
Bradley Greer | Software Engineer | London | 41 | 2012-10-13 | $132,000 |
Dai Rios | Personnel Lead | Edinburgh | 35 | 2012-09-26 | $217,500 |
Jenette Caldwell | Development Lead | New York | 30 | 2011-09-03 | $345,000 |
Yuri Berry | Chief Marketing Officer (CMO) | New York | 40 | 2009-06-25 | $675,000 |
Caesar Vance | Pre-Sales Support | New York | 21 | 2011-12-12 | $106,450 |
Doris Wilder | Sales Assistant | Sydney | 23 | 2010-09-20 | $85,600 |
Angelica Ramos | Chief Executive Officer (CEO) | London | 47 | 2009-10-09 | $1,200,000 |
Gavin Joyce | Developer | Edinburgh | 42 | 2010-12-22 | $92,575 |
Jennifer Chang | Regional Director | Singapore | 28 | 2010-11-14 | $357,650 |
Brenden Wagner | Software Engineer | San Francisco | 28 | 2011-06-07 | $206,850 |
Fiona Green | Chief Operating Officer (COO) | San Francisco | 48 | 2010-03-11 | $850,000 |
Shou Itou | Regional Marketing | Tokyo | 20 | 2011-08-14 | $163,000 |
Michelle House | Integration Specialist | Sydney | 37 | 2011-06-02 | $95,400 |
Suki Burks | Developer | London | 53 | 2009-10-22 | $114,500 |
Prescott Bartlett | Technical Author | London | 27 | 2011-05-07 | $145,000 |
Gavin Cortez | Team Leader | San Francisco | 22 | 2008-10-26 | $235,500 |
Martena Mccray | Post-Sales support | Edinburgh | 46 | 2011-03-09 | $324,050 |
Unity Butler | Marketing Designer | San Francisco | 47 | 2009-12-09 | $85,675 |
Howard Hatfield | Office Manager | San Francisco | 51 | 2008-12-16 | $164,500 |
Hope Fuentes | Secretary | San Francisco | 41 | 2010-02-12 | $109,850 |
Vivian Harrell | Financial Controller | San Francisco | 62 | 2009-02-14 | $452,500 |
Timothy Mooney | Office Manager | London | 37 | 2008-12-11 | $136,200 |
Jackson Bradshaw | Director | New York | 65 | 2008-09-26 | $645,750 |
Olivia Liang | Support Engineer | Singapore | 64 | 2011-02-03 | $234,500 |
Bruno Nash | Software Engineer | London | 38 | 2011-05-03 | $163,500 |
Sakura Yamamoto | Support Engineer | Tokyo | 37 | 2009-08-19 | $139,575 |
Thor Walton | Developer | New York | 61 | 2013-08-11 | $98,540 |
Finn Camacho | Support Engineer | San Francisco | 47 | 2009-07-07 | $87,500 |
Serge Baldwin | Data Coordinator | Singapore | 64 | 2012-04-09 | $138,575 |
Zenaida Frank | Software Engineer | New York | 63 | 2010-01-04 | $125,250 |
Zorita Serrano | Software Engineer | San Francisco | 56 | 2012-06-01 | $115,000 |
Jennifer Acosta | Junior Javascript Developer | Edinburgh | 43 | 2013-02-01 | $75,650 |
Cara Stevens | Sales Assistant | New York | 46 | 2011-12-06 | $145,600 |
Hermione Butler | Regional Director | London | 47 | 2011-03-21 | $356,250 |
Lael Greer | Systems Administrator | London | 21 | 2009-02-27 | $103,500 |
Jonas Alexander | Developer | San Francisco | 30 | 2010-07-14 | $86,500 |
Shad Decker | Regional Director | Edinburgh | 51 | 2008-11-13 | $183,000 |
Michael Bruce | Javascript Developer | Singapore | 29 | 2011-06-27 | $183,000 |
Donna Snider | Customer Support | New York | 27 | 2011-01-25 | $112,000 |
Name | Position | Office | Age | Start date | Salary |
The code for this example is simply:
$('#myTable').DataTable( $.fn.dataTable.ext.deepLink( [
'search.search', 'order', 'displayStart'
] ) );
You also need to include the deep linking script on your page:
Usage
The key element of using this script on your own pages is the $.fn.dataTable.ext.deepLink
function. This takes a single argument: an array of the options that you wish to allow the search parameter to specify, and it will return an object that contains these initialisation options which can be passed straight to the DataTable, as is the case above.
A white-list approach is used to limit which options can be used for security. For example, it is unlikely you would wish to allow a user to modify the ajax
, serverSide
or scrollY
parameters. If a parameter is given which isn't in the white-list, it will be ignored. Having said that, if you are using your application in an environment where you do wish any and all parameters to be used, you can specify all
as the only argument to the function, which will allow all parameters.
A simple example: allow the search.search
parameter to be set from the search string:
$('#myTable').DataTable( $.fn.dataTable.ext.deepLink( [
'search.search'
] );
Extending defaults
Since the deepLink()
function simply returns an object, you can provide defaults which can optionally be overridden by the search string, or vice-versa have an optional parameter that will override any parameter from the search string. This can be done using the jQuery.extend()
function with the returned object:
var searchOptions = $.fn.dataTable.ext.deepLink( [
'order'
];
var defaultOptions = {
order: [[ 2, 'desc' ]]
};
$('#myTable').DataTable(
$.extend( defaultOptions, searchOptions )
);
How does it work?
Now that we know how to use it, if you are interested in how it works, read on. Its actually very simple! Let's first step back to my standard response in the forum to say that the search string should be used to set the parameter value. If we assume that the entire search string is to be used to search the table (e.g. /table?mySearchTerm
) we might use:
$('#myTable').DataTable( {
search: {
search: location.search.replace(/^\?/, '')
}
} );
The key now is to break the search string into key value pairs. Slightly surprisingly there isn't an API for this in browsers, but its trivial to do with String.prototype.split
and decodeURIComponent()
:
$.fn.dataTable.ext.deepLink = function(whitelist) {
var search = location.search.replace(/^\?/, '').split('&');
var out = {};
for (var i = 0, ien = search.length; i < ien; i++) {
var pair = search[i].split('=');
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
...
}
return out;
};
### Casting values
The query string can only directly hold string values (it is a string itself after all), unless we use a data schema such as JSON. JSON isn't pretty to look at in a URL, so we want to avoid that here. The type always being a string is an issue in this case as certain DataTables parameters expect other types - for example `-init displayStart` must be a `Number` and not a `String` while `-init paging` is a Boolean. As such we need to [cast](https://en.wikipedia.org/wiki/Type_conversion) the string values into their typed counterparts:
```js
if (value === 'true') {
value = true;
}
else if (value === 'false') {
value = false;
}
else if (!value.match(/[^\d]/)) {
value = value * 1;
}
else if (value.indexOf('{') === 0 || value.indexOf('[') === 0) {
// Try to JSON parse for arrays and obejcts
try {
value = $.parseJSON( value );
}
catch(e){}
}
The downside to this is that it wouldn't be possible to set search.search
to true
since it would be cast to the boolean value by the above code. I feel this is a relatively unlikely situation to run into, but if you do, the above piece of code would need to be modified to suit your needs.
Writing nested values
You might have noticed in the above examples that search.search
is used a lot, since that is one of parameters that I expect to be used most commonly with this script. However, the Javascript object version of it is actually { search: { search: ... } }
- i.e. a nested object. To convert from the string notation, we can use a function which DataTables has built-in to build nested objects based on a dot delimited string: $.fn.dataTable.ext.internal._fnSetObjectDataFn
(this is used for columns.data
). This function isn't a documented API, but the next major version will see it promoted to be so (albeit with a more accessible name) as it is exceptionally useful for plug-ins and add-on scripts!
var setBuilder = $.fn.dataTable.ext.internal._fnSetObjectDataFn;
if (whitelist === 'all' || $.inArray(key, whitelist) !== -1) {
var setter = setBuilder(key);
setter(out, value);
}
Source and Git
The full documented source for this script can be found on GitHub. If you have any ideas for how it can be enhanced, pull requests are welcome!