Datatables / TableTools: format data as text when exporting to Excel

一世执手 提交于 2019-11-29 07:19:25

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

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];
                    }
                }
            }               
            }],

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.

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.

Aureltime

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

Tauqeer Afzal

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

Marquistador

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.

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

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!