Alphabet input search - Part I
Search is a core feature of DataTables - in fact it was the first feature that was implemented in the code, way back in 2007 as it was key to what DataTables was designed to do: let users find information in complex data sets quickly and easily. DataTables' search options have come along way since that initial work and provide a range of options through the search()
method and among others.
Often, however, you will wish to customise the search options of DataTables to match your own needs. This might be as simple as providing a custom input that fits in perfectly with your site's general UX, or you might want to use a complex search algorithm.
To meet this need, DataTables provides a custom search API which can be used to perform whatever search logic you wish. In this three part series of posts I will introduce this API, showing how to use it and provide custom search functions that match your specific needs. As a working example an alphabet search bar will be developed as part of this series showing you how various aspects of the DataTables plug-in system work.
- Part I (this post): Introducing customer search and showing a clickable alphabet filter
- Part II: Add user information showing the number of search results for each option in the filter
- Part III: Creating a feature plug-in for DataTables incorporating the previously developed code for reuse flexibility.
The alphabet search
Let's start at the end, by seeing what we are going to create in this post - a list of letters above a DataTable, which when clicked, will activate a table search, finding data that starts with the letter that was clicked upon in the first column:
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 |
Search plug-in
Search plug-ins for DataTables are attached to the $.fn.dataTable.ext.search
array. Simply push()
a function onto this array and DataTables will execute the function for each row in a table whenever it needs to perform a search operation. The function should then return true
or false
to indicate to DataTables if the row should be included in the result set (true
) or not (false
).
In the case of the alphabet search, we simply want to check the first letter of the first column of data (which can be obtained from the second parameter passed into the function, in combination with the charAt()
method) against a variable which stores the character that the user has activated the search upon (call it _alphabetSearch
).
That gives us this simple little function:
var _alphabetSearch;
$.fn.dataTable.ext.search.push( function ( settings, searchData ) {
if ( ! _alphabetSearch ) { // No search term - all results shown
return true;
}
if ( searchData[0].charAt(0) === _alphabetSearch ) {
return true;
}
return false;
} );
The DataTables manual contains detailed information about the search plug-in API if you are interested in finding out more information about this API.
Interface
The interface we want to present to the end user here is actually very simple. Just a list of the letters in the alphabet, A-Z. There is no DataTables specific code here, just simple jQuery manipulation of the DOM to create a div
element with a list of span
s inside, one for each letter, so I won't go into detail about this code, however there are a couple of points worth noting:
- A None option is include to clear the search term, allowing all entries in the table to be shown.
String.formCharCode
is used to convert an ASCII code to a letter.- The data property
letter
is used to store the letter to be used for the search term.
// DataTables initialisation
var table = $('#example').DataTable();
var alphabet = $('<div class="alphabet"/>').append( 'Search: ' );
$('<span class="clear active"/>')
.data( 'letter', '' )
.html( 'None' )
.appendTo( alphabet );
for ( var i=0 ; i<26 ; i++ ) {
var letter = String.fromCharCode( 65 + i );
$('<span/>')
.data( 'letter', letter )
.html( letter )
.appendTo( alphabet );
}
alphabet.insertBefore( table.table().container() );
The above is a simple case for the letters used in Latin script only, but it could be readily extended to use characters from any other alphabet, or also to include numeric values.
Behaviour
To activate a search we use a standard jQuery $().on()
click handler to listen for the click event. The listener will read the letter
data property for the element and assign it to the _alphabetSearch
variable we defined in our search function above and then use draw()
to redraw the table and have the new search term taken into account. It also does a little class manipulate to show visually which element is the active search term.
alphabet.on( 'click', 'span', function () {
alphabet.find( '.active' ).removeClass( 'active' );
$(this).addClass( 'active' );
_alphabetSearch = $(this).data('letter');
table.draw();
} );
Styling
We have a very simple DOM structure for our alphabet list, consisting of a div
with span
elements in it. To display neatly we can use the CSS display: table
property to have the alphabet shown as a flexible width, nicely laid out grid. A couple of other styles are also added just to provide visual feedback to the end user.
div.alphabet {
display: table;
width: 100%;
margin-bottom: 1em;
}
div.alphabet span {
display: table-cell;
color: #3174c7;
cursor: pointer;
text-align: center;
width: 3.5%
}
div.alphabet span:hover {
text-decoration: underline;
}
div.alphabet span.active {
color: black;
}
Complete code
The Javascript shown above is complete, but if you want a copy and paste solution, rather than to assemble the code, the entire code block used for this example is shown below:
var _alphabetSearch = '';
$.fn.dataTable.ext.search.push( function ( settings, searchData ) {
if ( ! _alphabetSearch ) {
return true;
}
if ( searchData[0].charAt(0) === _alphabetSearch ) {
return true;
}
return false;
} );
$(document).ready(function() {
var table = $('#example').DataTable();
var alphabet = $('<div class="alphabet"/>').append( 'Search: ' );
$('<span class="clear active"/>')
.data( 'letter', '' )
.html( 'None' )
.appendTo( alphabet );
for ( var i=0 ; i<26 ; i++ ) {
var letter = String.fromCharCode( 65 + i );
$('<span/>')
.data( 'letter', letter )
.html( letter )
.appendTo( alphabet );
}
alphabet.insertBefore( table.table().container() );
alphabet.on( 'click', 'span', function () {
alphabet.find( '.active' ).removeClass( 'active' );
$(this).addClass( 'active' );
_alphabetSearch = $(this).data('letter');
table.draw();
} );
} );