6
votes

I am using the Datatables TableTools plugin in order to provide an Export to Excel option for a table on my page.

In general everything works as intended. My only issue is that I would need all the data resp. the columns in the resulting Excel table being formatted as text as otherwise I am losing data in some columns.

Examples: - I have a column that has leading zeros (e.g. 0022) which only appears with the leading zeros cut off (e.g. 22) in the Excel file if this is not formatted as text. - Another column contains 19-digit account numbers (e.g. 1234567890123456789) which appears with the last four digits being changed to zeros (e.g. 1234567890123450000) in the Excel file if this is not formatted as text.

Is there any way I can set this in my Datatables / TableTools initialisation so that it always exports all data as text into the Excel file ?

Many thanks for any help with this, Tim.

9

9 Answers

4
votes

TableTools does not create a real excel file, it creates a csv file instead. Those contain only raw data, no formatting. Although the leading zeros are there, Excel usually will not show them. You have several options here:

  • change the formatting from within Excel
  • open the csv file from Excel's open dialog, from which you should be able to mark columns as text (you might need to change the file type to txt)
  • add quotes around the data
  • create a real excel file via some external library
17
votes

I tried the first option given by Aureltime but I found a little side effect. If the column only contains numbers and you use the render function, the sorting option doesn't work. Hopefully, from 1.10.12 datatables version there is a new option to customize data before creating the excel file.

In this customize function I added the /u002C and it works perfect, even the sorting of numbers.

        "buttons": [{
            extend: 'excel',
            exportOptions: {
                orthogonal: 'sort'
            },
            customizeData: function ( data ) {
                for (var i=0; i<data.body.length; i++){
                    for (var j=0; j<data.body[i].length; j++ ){
                        data.body[i][j] = '\u200C' + data.body[i][j];
                    }
                }
            }               
            }],
5
votes

I have the solution to this problem.

It was broken my head very much time... So the explain is below this:

  1. It fix works fine in DatatableJS version 1.10.11 (for HTML Excel export option)
  2. Open datatables.js and search this: "DataTable.ext.buttons.excelHtml5 = {"
  3. Search in the follow lines until take this code, and comment it:

             cells.push( typeof row[i] === 'number' || (row[i].match && $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) && row[i].charAt(0) !== '0') ?
                '<c t="n"><v>'+row[i]+'</v></c>' :
                '<c t="inlineStr"><is><t>'+(
                    ! row[i].replace ?
                        row[i] :
                        row[i]
                            .replace(/&(?!amp;)/g, '&amp;')
                            .replace(/</g, '&lt;')
                            .replace(/>/g, '&gt;')
                            .replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''))+ // remove control characters
                '</t></is></c>'                                                      // they are not valid in XML
            );
    
  4. Put this new code :

                cells.push( '<c t="inlineStr"><is><t>'+(
                            ! row[i].replace ?
                                row[i] :
                                row[i]
                                    .replace(/&(?!amp;)/g, '&amp;')
                                    .replace(/</g, '&lt;')
                                    .replace(/>/g, '&gt;')
                                    .replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''))+ // remove control characters
                        '</t></is></c>'                                                      // they are not valid in XML
                    );
    
  5. Save your datatables.js

  6. Enjoy your holy Text Cells Forever!!

This solution helps to maintain the number, date, and decimal format's.

I changed the code to force to write in text format all values from the HTML to the XLSX.

If anybody have a question about this solution, I will try to response all of them questions.

Thanks to all.

2
votes

I would like to expand on Richards answer. Like Richard, I could not figure out the solution based on the Datatables documentation. I wanted an excelHtml5 export with all fields being exported as text only.
Richards solution helped me get to the solution that I will post below.

For Datatables 1.10.12 the html5 buttons code appears in a separate file buttons.html5.js.

As Richard noted, search for the DataTable.ext.buttons.excelHtml5 block.

The piece of code I was interested in was:

// Detect numbers - don't match numbers with leading zeros or a negative
// anywhere but the start
if ( typeof row[i] === 'number' || (
        row[i].match &&
        $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) &&
        ! $.trim(row[i]).match(/^0\d+/) )
) {
    cell = _createNode( rels, 'c', {
        attr: {
            t: 'n',
            r: cellId
        },
        children: [
            _createNode( rels, 'v', { text: row[i] } )
        ]
    } );
}
else {
    // Replace non standard characters for text output
    var text = ! row[i].replace ?
        row[i] :
        row[i]
            .replace(/&(?!amp;)/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');

    cell = _createNode( rels, 'c', {
        attr: {
            t: 'inlineStr',
            r: cellId
        },
        children:{
            row: _createNode( rels, 'is', {
                children: {
                    row: _createNode( rels, 't', {
                        text: text
                    } )
                }
            } )
        }
    } );
}

In order to make the excelHtml5 button export ONLY text, I removed the IF block that would identify a field as a potential number. Our customer also had a specific request to have '<>' in any field that was blank so I removed the two replace methods for < and >.

// Replace non standard characters for text output
var text = ! row[i].replace ?
    row[i] :
    row[i]
        .replace(/&(?!amp;)/g, '&amp;')
        .replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');

cell = _createNode( rels, 'c', {
    attr: {
        t: 'inlineStr',
        r: cellId
    },
    children:{
        row: _createNode( rels, 'is', {
            children: {
                row: _createNode( rels, 't', {
                    text: text
                } )
            }
        } )
    }
} );

This change allows the excel button to export all values as text. Excel no longer switches my < and > and my numbers are all text, no scientific notation.

1
votes

This specific problem has been answered elegantly in this post - https://stackoverflow.com/a/165052/6169225. Let's say that you have an integer your_integer that you want displayed as a string (i.e. the leading zeros displayed). Then you simply format it as such before you export to excel - ="<your_integer>". When the excel doc auto-downloads, your integer will already display as a string using this method.

0
votes

Update :

From datatables 1.10.8 and introduction of Buttons API, tabletools is deprecated and here is the way to do it via buttons API:

Demo here

It extends the excel button with exportOptions parameter which allow few options, one is orthogonal when you can say that it should use the 'sort' type :

exportOptions: {
                orthogonal: 'sort'
            }

After you need to precise the sort type and which columns should be impacted with the columnDefs datatable option :

columnDefs: [{
       targets:[1],
       render: function(data, type, row, meta){
          if(type === 'sort'){
             //data = ' ' + data ;
              return "\u200C" + data ; 
          }

          return data ;   

       }
    }]

Here the second column ( zero indexed) is considered. For the 'sort' type, we prefix the date with the ZERO WIDTH NON-JOINER so excel will consider it as string. Didnt notice any side effects.

Enjoy

there is a way to do it via the tabletools plugin of datatables.

Using Stop Excel from automatically converting certain text values to dates ,

and the fncellrender button option, the solution is to use the fnCellRender option on the xls button like this :

{
"sExtends":    "xls", 
"fnCellRender": function ( sValue, iColumn, nTr,iDataIndex ) {
     if ( iColumn === colIndexOfString ) {
         return '"=""' + sValue + '"""' ;
         }
     return sValue;
     }
}

This way data is extracted in csv file with the special characters needed to make Excel considered them as string and avoid to use automatic type detection.

And yes now you can keep your leading and trailing zeros

0
votes

Solution of datatable expord CSV with special characters. Find charset from https://cdn.datatables.net/buttons/1.1.2/js/buttons.html5.js or https://cdn.datatables.net/buttons/1.1.2/js/buttons.html5.min.js

and change it to UTF-8-BOM from UTF-8

0
votes

For the numbers that are 19 digits, the issue is actually Excel rounding the numbers when it opens the data. Please see this thread for more info and possible workarounds: https://datatables.net/forums/discussion/comment/132633#Comment_132633

0
votes

Below code will help you to create a query data table with export to Text file as an custom option. And also included out-of-box copy, excel, csv.

     $('#tableid').DataTable({
           buttons: [
                {
                    extend: 'copyHtml5',
                    filename: function() {
                        return "Copy Table";
                    }
                },
                {
                    extend: 'excelHtml5',

                    filename: function() {
                        return "Export To Excel";
                    }
                },
                {
                    extend: 'csvHtml5',

                    filename: function() {
                        return "Export to CSV";
                    }
                },
                {
                    text: 'Text',
                    footer: false,
                    header: false,
                    exportOptions: {
                        orthogonal: 'sort'
                    },
                    action: function(e, dt, node, config) {

                        var data = dt.buttons.exportData();
                        var retContent = [];
                        var retString = '';
                        for (var i = 0; i < data.body.length; i++) {
                            var text = '\u200C' + data.body[i];
                            retContent.push(text);
                        }
                        retString = retContent.join(',\r\n');
                        $.fn.dataTable.fileSave(
                            new Blob( [ retString ] ),
                            "Export to text"+ ".txt"
                        );
                    }
                }
            ]
        });

Libraries included are:

  1. datatables.min.js
  2. dataTables.bootstrap4.min.js
  3. dataTables.buttons.min.js
  4. buttons.flash.min.js
  5. jszip.min.js
  6. vfs_fonts.js
  7. buttons.html5.min.js

and found above libraries in this link https://editor.datatables.net/examples/extensions/exportButtons