Ellipsis renderer
During your work with DataTables, there will be occasions when the data obtained from the source feed is not in the format that you wish to show to your end users. For this DataTables has support for data renderers through columns.render
. This option can be used as a function to perform data transformation (its a Javascript function, so anything you want!) and is called whenever DataTables requires data for that cell. Indeed, this option is also how DataTables provides its orthogonal data support.
The following is a short list of use cases where renderers can be useful:
- Convert a date / time to a localised format
- Format numbers for currency, readability and precision
- Security to prevent XSS attacks
- Shorten a long string
This article will detail how a renderer operates and can be constructed by implementing the final option in the list above as an example: long text will be shorted with an ellipsis showing that the text has been truncated.
Example
The table below shows an example - the first column uses ellipsis at 10 characters and does not allow words to be broken, while the second column uses ellipsis at 15 characters and does allow words to be truncated part way through. The example table also has Responsive enabled.
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 |
Simple renderer
Let's start by considering the simplest case possible - an HTML sourced table where we want to limit the number of characters in the first column to be no more than ten characters:
$('#myTable').DataTable( {
columnDefs: [ {
targets: 0,
render: function ( data, type, row ) {
return data.substr( 0, 10 );
}
} ]
} );
The code above created a DataTable on the #myTable
element and columnDefs
is used to assign column options to the first column only (columnDefs.targets
). The important part here is the use of the rendering function - columns.render
. We use substr()
to limit the data to only 10 characters.
This is trivial to implement, but there are a few issues:
- There is no indication to the end user that the data has been truncated
- Search and ordering data will also be truncated.
Let's address each in turn - to indicate to the end user that the data has been truncated we use ellipsis (…
). A trivial check to see if the string will be truncated gives us the ability to decide if ellipsis should be added or not:
render: function ( data, type, row ) {
return data.length > 10 ?
data.substr( 0, 10 ) +'…' :
data;
}
To address the second point we can use the second parameter passed into the function, which is DataTables' orthogonal data type indicator - only if it is display
do we wish to show ellipsis. Now we have:
render: function ( data, type, row ) {
return type === 'display' && data.length > 10 ?
data.substr( 0, 10 ) +'…' :
data;
}
Easy!
Reusable renderers
The above is a few trivial lines of code, but if you are working on any web-site which has more than one page you will want to follow the Don't Repeat Yourself (DRY) principle of good software development.
Since functions are first class elements in Javascript we can store the rendering function in a variable and then assign it to the columns.render
option as needed. DataTables provides an object that can be used as a common location to store all renderers: DataTable.render
.
If we continue our ellipsis example we might have:
DataTable.render.ellipsis = function () {
return function ( data, type, row ) {
return type === 'display' && data.length > 10 ?
data.substr( 0, 10 ) +'…' :
data;
}
};
Then to use this with DataTables we can use:
$('#myTable').DataTable( {
columnDefs: [ {
targets: 0,
render: DataTable.render.ellipsis()
} ]
} );
That rendering function can then be used for multiple tables, over multiple pages - just save the renderer code into a file that is loaded onto your pages (dataTables.plugins.js
for example).
Configuration options
You will have noticed that we define ellipsis
as a function that returns a function - this isn't particularly useful in this simple case, but for more complex cases, and continuing the DRY concept, the outer function can be used to configure the renderer. In our ellipsis example this can be the ability to define the number of characters that will be shown - for example:
DataTable.render.ellipsis = function ( cutoff ) {
return function ( data, type, row ) {
return type === 'display' && data.length > cutoff ?
data.substr( 0, cutoff ) +'…' :
data;
}
};
Now the renderer can be used to define the number of characters as shown:
render: DataTable.render.ellipsis( 10 )
render: DataTable.render.ellipsis( 15 )
render: DataTable.render.ellipsis( 20 )
etc
Even for cases where configuration options are not required it is a good idea to use a container function, simply for consistency. Most rendering functions do require some kind of configuration, so it is easier if all rendering plug-ins are presented as functions that need to be executed.
Ellipsis rendering plug-in
Now that the groundwork for how to create a DataTables rendering plug-in have been laid, let's built the ellipsis plug-in up to provide greater utility with the following features:
- Variable length truncation
- Show the full string in a tooltip
- Option to disallow breaking in the middle of a word
- Ability to escape HTML for XSS security
The following function provides all of these features
DataTable.render.ellipsis = function ( cutoff, wordbreak, escapeHtml ) {
var esc = function ( t ) {
return t
.replace( /&/g, '&' )
.replace( /</g, '<' )
.replace( />/g, '>' )
.replace( /"/g, '"' );
};
return function ( d, type, row ) {
// Order, search and type get the original data
if ( type !== 'display' ) {
return d;
}
if ( typeof d !== 'number' && typeof d !== 'string' ) {
return d;
}
d = d.toString(); // cast numbers
if ( d.length < cutoff ) {
return d;
}
var shortened = d.substr(0, cutoff-1);
// Find the last white space character in the string
if ( wordbreak ) {
shortened = shortened.replace(/\s([^\s]*)$/, '');
}
// Protect against uncontrolled HTML input
if ( escapeHtml ) {
shortened = esc( shortened );
}
return '<span class="ellipsis" title="'+esc(d)+'">'+shortened+'…</span>';
};
};
Breaking the function down you'll be able to see that the above is fairly basic Javascript. Only display
data types will have their length truncated (as discussed above) and only strings are manipulated. The string is truncated and a regular expression is used to strip back to the last work if the no-word break option is enabled. Finally a span
is returned which contains the shortened string with an ellipsis and a browser tooltip provided by the title
attribute (you could also use Javascript tooltip libraries if you prefer).
Source
The ellipsis data renderer is detailed on its plug-ins page and is available on the DataTables CDN (keep in might that you might wish to combine multiple plug-ins into a single file for loading efficiency):
The source is also available on GitHub and pull requests for improvements are always welcome.
Sharing plug-ins
If you create a rendering plug-in that you would like to share with the DataTables community - first of all - thank you! Please send pull requests to the DataTabels plug-ins repo in the dataRender
directory. A documentation block should also be included to detail what the plug-in does and how it can be used (please refer to existing plug-ins for a template).
Enjoy!