Colvis error when using headerCallback to change col headings

Colvis error when using headerCallback to change col headings

edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0
edited December 11 in Free community support

I just upgraded from dt 1.13 -> 2.1 and found that the colVis buttons crashes when changing the column headers.
My use-case is that I want to include the sum total in the col header and also use the colVis button feature.

<link href="https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.css" rel="stylesheet" />
<script src="https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js"></script>

<script>
datatable = $('.datatableclass').DataTable( {
  "dom": "<'row'<'col-sm-3'l><'col-sm-4'i><'col-sm-5'f>>" +
  "<'row'<'col-sm-12'tr>>" +
  "<'row'<'col-sm-6'i><'col-sm-6'p>>",
  "ajax": { ... },
  buttons: [
    { extend: 'csvHtml5',
      text: 'Export Table',
      exportOptions: {columns: ':gt(0):visible'},
    },
    { extend: 'colvis',
      text: 'Columns',
      columns: [2,3,4, ':gt(5)']
    }
  ],
 "headerCallback": function( thead, data, start, end, display ) {
    var api = this.api();

    $( api.column( 11 ).header() ).html('Billed')); // Works if this line is removed.
},
...
</script>

<table class="table datatableclass">
</table>

The code is simplified here shows the problem, but this all worked using dt v1.13

Browser console shows the following error:

Uncaught TypeError: o is undefined
    _columnText https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:51
    text https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:51
    i https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    _buildButton https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    _expandButton https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    _expandButton https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    _expandButton https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    add https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    _constructor https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    A https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    <anonymous> https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:40
    jQuery 7
...

This question has accepted answers - jump to:

Answers

  • allanallan Posts: 63,676Questions: 1Answers: 10,497 Site admin

    Can you link to a test case showing the issue so I can trace the problem through and see what is going wrong?

    Thanks,
    Allan

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974
    edited December 11 Answer ✓

    When available you should always use Datatables API's to update the table. Use column().title() to update the header.values. I built a test case, using your code snippet, to show this:
    https://live.datatables.net/tujumosi/1/edit

    Also it looks like Colvis doesn't automatically pickup these changes. If you need this then the only way I see to update the Colvis button is to remove and re-add it. This is also shown in the test case.

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    Hi @kthorngren,
    The reason I'm using the headerCallback is because I want to show the sum of the values in the header... not sure I can do that with column().title (?)

    Here's the actual code:

    "headerCallback": function( thead, data, start, end, display ) {
      var api = this.api();
                                
      var intVal = function ( i ) {
        return typeof i === 'string' ? i.replace(/[\$,]/g, '')*1 :typeof i === 'number' ? i : 0;
      };
    
      $( api.column( 11 ).header() ).html('Billed<br/>'+
      api.column( 11, {"filter": "applied"} ).data().reduce( function ( a, b ) {
        return intVal(a) + intVal(b);
      }, 0 ).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')
    );
    

    I don't need the Colvis button to pick up the new heading (I'd rather it didn't because I don't want the numbers in there). I just need to show the sum in the header somewhere.

    Ideally, something like:

    <thead>
    <tr><th>Billed</th><th>Paid</th></tr>
    <tr><th>$10,213.21</th><th>$3,213.42</th></tr>
    </thead>
    

    would be great, but I don't know if that's possible in datatables because I'm defining the columns using columns: [ ... ] rather than <thead>...</thead>.

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    Hi @allan,
    I'm using ajax for the data, so not sure how to go about making a test case. I'll try to replicate it with static data and create a test case if I get that far.

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0
    edited December 11

    @kthorngren You're right - changing it all to api.column( 20 ).title('...') fixed it.
    The problem now is that the colvis labels are also picking up the numbers, which I don't want. Is there some way to show the numbers in the second row within the header rather than Title<br/>$231.23 and then have the colvis labels only pick up the first row within the table head?

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974

    Take a look at the docs and last example of the column().title() docs to see how to set the value in the 2nd header row.

    I'm using ajax for the data, so not sure how to go about making a test case. I'll try to replicate it with static data and create a test case if I get that far.

    We don't need to see the full solution in a test case. The test case only needs to demonstrate the problem. This issue is likely not Ajax related but could be. You can use one of the ajax templates found here if you want to build a test case with ajax loaded data.

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0
    edited December 11

    @kthorngren

    When I set title('100', 1);, it crashes with the following log:

    Uncaught TypeError: a[(intermediate value)] is undefined
        pe https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        xe https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        iterator https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        xe https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        t https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        X.extend/e[a.name]< https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        xe https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        iterator https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
        xe https://cdn.datatables.net/v/bs/jszip-3.10.1/dt-2.1.8/b-3.2.0/b-colvis-3.2.0/b-html5-3.2.0/b-print-3.2.0/fc-5.0.4/fh-4.0.1/sl-2.1.0/datatables.min.js:30
    

    Could it have something to do with my not setting the THEAD in my table definition? I'm not sure how to do that because the columns are all defined with the columns: [] option.

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974

    The columns.title doesn't support building complex headers. This is from the docs:

    Please note that when constructing a header, DataTables can only construct a simple header with a single cell for each column. Complex headers with colspan and rowspan attributes must either already be defined in the document, or be constructed using standard DOM / jQuery methods. Furthermore, if you use this property with a multi-row header in the DOM, the title will be set for the first row in the header only.

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    Thanks @kthorngren - that makes sense.
    Is there some neat way to create a <thead> with 2 rows in it, or do I just need to define my table with two header rows and a bunch (about 50) empty <th> tags?

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974

    Is there some neat way to create a <thead> with 2 rows in it,

    Use Stack Overflow to research Javascript or jQuery code snippets that will work for your specific environment.

    or do I just need to define my table with two header rows and a bunch (about 50) empty <th> tags?

    You don't want to create more columns than is in the table data or else you will get the Incorrect column count.

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    @kthorngren

    If I define my table like this (number of columns match):

    <table class="table datatableclass">
      <thead>
      <tr><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                 <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                  <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                  <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th></tr>
                      
                  <tr><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                  <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                  <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th>
                  <th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th></tr>
      </thead>
    </table>
    

    Datatables assigns the column titles to both rows. Is there some way to have it assign the title (defined in the columns: [] option) only to the top row?

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974

    I built a simple test case for you:
    https://live.datatables.net/muqeheze/1/edit

    It does populate both header rows. According to the columns.title docs it should only populate the first row:

    Furthermore, if you use this property with a multi-row header in the DOM, the title will be set for the first row in the header only.

    @allan will need to comment if this is a bug in the columns.title code or a documentation bug. As a workaround you can clear the second header values using columns().titles() in initComplete like this:
    https://live.datatables.net/sexedoqu/1/edit

    You may also want to use orderCellsTop to remove the sorting events from the second header.

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    @kthorngren columns().titles() clears the second row, which is good, but it does so after the numbers have been set (in the headerCallback), so it's all blank with no sums there. Now I need some way to re-generate the heading so the numbers go back - e.g. calling headerCallback manually. Maybe something like table.draw(), but for the header only?

    This problem goes away if the titles are applied only to the first row, but I'll wait to hear back from @allan on that one.

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974
    edited December 12 Answer ✓

    Then that means headerCallback executes, the first time, before initComplete. In that case move the code to clear the second header row into headerCallback. For example:
    https://live.datatables.net/sexedoqu/2/edit

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0
    edited December 12

    @kthorngren That fixed that issue - I just found one (hopefully last) problem.
    Here's a test case: https://live.datatables.net/tujumosi/2/edit

    When using two rows in the heading, the selector for colVis doesn't work as expected. Using columns: [2, ':gt(3)'] will show the colvis list as columns 2,4,5,0,1,3 when there are 6 total columns. In other words, it seems to append the excluded columns to the end of the list.
    This only happens when there are two rows in the <thead>.

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974
    Answer ✓

    Using :gt(3) will select all th elements greater than index 3. This includes the second header row. You need to set a range something like less than index 6 (first th in second row) and greater than 3, for example: :lt(6):gt(3).

    https://live.datatables.net/sexajiso/1/edit

    Kevin

  • edwardiv1edwardiv1 Posts: 23Questions: 4Answers: 0

    Thanks for all your help @kthorngren - that fixed it. Seems to be all be working correctly now.

Sign In or Register to comment.