Alphabet input search - Part II
Continuing a three part series of posts exploring the DataTables custom search options, API and feature plug-ins, this second post extends the alphabet search control introduced in part I of this series to give quick visual feedback to the end user for search terms. This visual information will indicate how many records are in the table for each search option. This is done through use of the DataTables API and displaying an information element using jQuery.
The alphabet search
Before exploring the code in this post, the following example shows what we will be building here.
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 |
Mouse control
First consider how we wish to display the additional search information to the end user. As you will be able to see from the example above, a simple box with a number is shown below each letter in the alphabet as the user moves their mouse over the characters. The number indicates how many records are available for that search term (how that number is calculated is discussed below).
This is primarily simple Javascript and jQuery rather than being DataTables specific, so I won't delve into much detail here, but basically what we do is attach the element for the number box (info
below) to the alphabet container (alphabet
from the code developed in part I). As the mouse enters a search term element (a span
tag) the information element is made visible with its content and position being updated to be suitable for the search term. As the mouse is removed, the information element is also removed.
var info = $('<div class="alphabetInfo"></div>')
.appendTo( alphabet );
alphabet
.on( 'mouseenter', 'span', function () {
info
.css( {
opacity: 1,
left: $(this).position().left,
width: $(this).width()
} )
.html( $(this).data('match-count') )
} )
.on( 'mouseleave', 'span', function () {
info.css('opacity', 0);
} );
Data attributes
In the code above, the search count for each letter is read from the data attribute match-count
- for example, you could consider the HTML to look like:
<div class="alphabet">
<span data-match-count="57">None</span>
<span data-match-count="3">A</span>
<span data-match-count="4">B</span>
<span data-match-count="5">C</span>
...
</div>
Our task now is simply to add those data attributes to the alphabet elements as they are created.
To get the data that is available in the first column we can use the DataTables column().data()
method. Passing in an index of 0
to the column()
method will retrieve the data for the first column, which can than be iterated over to count the number of times each character appears as the first letter in the data set.
For this we can write a simple function to bin the data, producing an object which has a count for each letter (the absence of a letter in the object represents a zero count):
function bin ( data ) {
var letter, bins = {};
for ( var i=0, ien=data.length ; i<ien ; i++ ) {
letter = data[i].charAt(0).toUpperCase();
if ( bins[letter] ) {
bins[letter]++;
}
else {
bins[letter] = 1;
}
}
return bins;
}
The resulting object might look like:
{
"A": 3,
"B": 4,
"C": 5,
...
}
Finally we call that function with the data from column().data()
and then use the binned data when creating the alphabet (refer to part I):
var columnData = table.column(0).data();
var bins = bin( columnData );
$('<span class="clear active"/>')
.data( 'letter', '' )
.data( 'match-count', columnData.length )
.html( 'None' )
.appendTo( alphabet );
for ( var i=0 ; i<26 ; i++ ) {
var letter = String.fromCharCode( 65 + i );
$('<span/>')
.data( 'letter', letter )
.data( 'match-count', bins[letter] || 0 )
.addClass( ! bins[letter] ? 'empty' : '' )
.html( letter )
.appendTo( alphabet );
}
Part II completed code
The complete code that is used for the example at the top of this page, including the code that was developed in part I of this series is shown below:
Javascript
var _alphabetSearch = '';
$.fn.dataTable.ext.search.push( function ( settings, searchData ) {
if ( ! _alphabetSearch ) {
return true;
}
if ( searchData[0].charAt(0) === _alphabetSearch ) {
return true;
}
return false;
} );
function bin ( data ) {
var letter, bins = {};
for ( var i=0, ien=data.length ; i<ien ; i++ ) {
letter = data[i].charAt(0).toUpperCase();
if ( bins[letter] ) {
bins[letter]++;
}
else {
bins[letter] = 1;
}
}
return bins;
}
$(document).ready(function() {
var table = $('#example').DataTable();
var alphabet = $('<div class="alphabet"/>').append( 'Search: ' );
var columnData = table.column(0).data();
var bins = bin( columnData );
$('<span class="clear active"/>')
.data( 'letter', '' )
.data( 'match-count', columnData.length )
.html( 'None' )
.appendTo( alphabet );
for ( var i=0 ; i<26 ; i++ ) {
var letter = String.fromCharCode( 65 + i );
$('<span/>')
.data( 'letter', letter )
.data( 'match-count', bins[letter] || 0 )
.addClass( ! bins[letter] ? 'empty' : '' )
.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();
} );
var info = $('<div class="alphabetInfo"></div>')
.appendTo( alphabet );
alphabet
.on( 'mouseenter', 'span', function () {
info
.css( {
opacity: 1,
left: $(this).position().left,
width: $(this).width()
} )
.html( $(this).data('match-count') )
} )
.on( 'mouseleave', 'span', function () {
info.css('opacity', 0);
} );
} );
CSS
div.alphabet {
position: relative;
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;
}
div.alphabet span.empty {
color: red;
}
div.alphabetInfo {
display: block;
position: absolute;
background-color: #111;
border-radius: 3px;
color: white;
top: 2em;
height: 1.8em;
padding-top: 0.4em;
text-align: center;
z-index: 1;
}
Next
In the concluding part of this series, next week we will take the alphabet control that has been developed here and create a reusable DataTables feature plug-in allowing this input control to be used by any DataTable with a single line of code.