Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag for United States of America

asked on

How do I implement "drawCallback" in Datatables and why does it work?

Here's the code I've been using for my Datatables:


$(document).ready(function () {
      $('#dtOrderExample').DataTable({       "order": [[ 1, "asc" ]],       "pageLength" : 10,       "ordering": true,       "paging": true,       "searching": true,       "info":true,       "columnDefs": [ {           "targets": 'no-sort',           "orderable": false          }]       });            $('[data-toggle="tooltip"]').tooltip()      });

Open in new window

Just now I realized that the tooltips don't work like they should if I do any kind of sorting on the table itself. 


Apparently, this is a known problem. According to https://stackoverflow.com/questions/39240361/datatables-and-bootstrap-tooltips, every time you redraw the table, you have to reinitialize the tooltip functionality. 


This puts me in some uncharted territory. While the solution seems simple enough, I can't get it to work and I'm interested in knowing WHY "drawCallBack" works and what it is.


Also, I need to some guidance on this piece. This is what the above URL recommends, but I'm implementing incorrectly and I'm not sure what I'm doing wrong:


$(document).ready(function () {
      $('#dtOrderExample').DataTable({       "order": [[ 1, "asc" ]],       "pageLength" : 10,       "ordering": true,       "paging": true,       "searching": true,       "info":true,       "columnDefs": [ {           "targets": 'no-sort',           "orderable": false          }]       });    "drawCallback": function(settings) {          $('[data-toggle="tooltip"]').tooltip();    }           });

Open in new window

The error is "Unexpected token." It's referring to a colon (:) on this line:


"drawCallback": function(settings) {  
      $('[data-toggle="tooltip"]').tooltip();
   }


Where am I blowing it and, assuming this is the right way to do things, why does it work?

SOLUTION
Avatar of lenamtl
lenamtl
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Bruce Gust

ASKER

Lenamtl and Scott!

If I'm not mistaken, you both recommended the same thing, yes?

That's why I'm giving you both credit, but I do want to make sure that I have barked up the correct tree.

Lenamtl, I used your code that you had on your live demo, but (and this is for either one of you), why does it work?

From what I could gather from Google, when DataTables does a search, it refreshes itself in a way where any tooltip functionality is going to be compromised. How does "drawCallback" fix that?

Thanks!

This is what resulted in charred dragon flesh (the dragon has been slayed...)!

   <script>
$(document).ready(function () {
      $('#dtOrderExample').DataTable({
      "order": [[ 1, "asc" ]],
      "pageLength" : 10,
      "ordering": true,
      "paging": true,
      "searching": true,
      "info":true,
      "columnDefs": [ {
          "targets": 'no-sort',
          "orderable": false
         }],
         drawCallback: function () {
           $("[data-toggle='tooltip']").tooltip({
            container: 'body'
           });
         }
      });
    
});
</script>

Open in new window

Hey Bruce,

Scott has already provided the fix for your problem, so the points belong to him, but I'll try and explain the reasoning behind it.

When you call the DataTable() method on an element, you have the ability to pass in various options, and these options are passed in as properties of an Object. In JS, an Object is defined using the curly brackets. Each property is an option, and if you look at the documentation, it will tell the valid values for each property - could be a string, could be a number, could be an array, could be a callback (a function that will be called at some point).

Effectively you'd do something like this:

let myOptions = {
  optionName1 : "Option Value",
  optionName2 : 123,
  optionName3 : true,
  optionName4 : function(x) { alert("I'm a callback") }
}

$('#someTable').DataTable(myOptions);

Open in new window

If you look closely at your code, you'll see that the Options object finished before the drawCallback line

// this is the options Object
({
  "order": [[ 1, "asc" ]],
  "pageLength" : 10,
  "ordering": true,
  "paging": true,
  "searching": true,
  "info":true,
  "columnDefs": [ {
    "targets": 'no-sort',
    "orderable": false
  }]
});
// and this is just tagged on - hence the error:
"drawCallback": function(settings) {   
  $('[data-toggle="tooltip"]').tooltip();
}

Open in new window

Hope that all makes sense
Chris is better at explaining this but, "If you look closely at your code, you'll see that the Options object finished before the drawCallback line " is exactly what stuck out for me.


One thing I missed in my explanation. In your original code, you have this (forget about the datatables bit for a sec):

$(document).ready(function () {
    $('[data-toggle="tooltip"]').tooltip()
});

So, that will fire the tooltip() code when the document is first ready. It works because at that point, the [data-toggle="tooltip"] element exists in the DOM. Once DataTables is initiated and re-drawn (sorted / refreshed), the [data-toggle="tooltip"] is re-created, but the tooltip() event isn't fireed again because it only fired when the document was first ready.

So --- you need to re-call it each time the DataTable is redrawn, and we have a function that is fired every time a redraw happens - you define it with the drawCallback property

I get it and I'm just now realizing that Scott was the first one to the party, so I apologize Scott...

Chris, here's what I'm hearing:

When DataTables creates a table, it's referred to as having "drawn" it (https://datatables.net/reference/option/drawCallback). The tooltip dynamic is something that needs to be coded as an option within the Datatables syntax because of the way it represents a "callBack," or, to use DataTables nomenclature, a "drawCallback."

A callback function is executed after the current effect is 100% finished (https://www.w3schools.com/jquery/jquery_callback.asp). Without placing the tooltip dynamic within the list of DataTables options / properties, something is going to go south and that's why I was running into either a performance issue or an outright error.

Correct?

Thank you!
Hi,

First Datatables has tooltip, toggle and other features that usually get conflict with custom code and/or with Bootstrap. So always be carefull when use this with your custom code, always use what Datatables offer first.

I'm using Datatables a lot and I never use the tooltip, I do prefer just to use the title alone but in both case title cause issue in some setup with responsive and other plugins (this may have been fixed recently), so I try to avoid it.

The problem you had is that you called the function outside the Datatables using the wrong method.

Here is the correct method to do it from outside, this is the code I provided for this
$('#example').on('draw.dt', function () {  $('[data-toggle="tooltip"]').tooltip(); }); 

Open in new window

 
You may need to call it from outside in some scenario depending how you load the table and if the table is dynamic or not.

Usually we specify the container for example body.
I know this is working without it but this can prevent issues depending of the other code and plugins
So I recommend to specify it.
drawCallback: function () {
   $("[data-toggle='tooltip']").tooltip({
     container: 'body'
  });

Open in new window


Now from the code example to display the tooltip using Ajax and external data from txt file.

This set the tooltip for the column
{ "data": "name",
        createdCell: function (td, cellData) {
         $(td)
         .attr('data-toggle', 'tooltip')
         .attr('title', '')
         .attr('data-placement', 'top')
         .attr('data-original-title', 'Name');


       },

Open in new window

and this call the function
 drawCallback: function () {
      $("[data-toggle='tooltip']").tooltip({
        container: 'body'
      });
    }

Open in new window

Thanks, lenamtl! I'll add that to my notes! I appreciate it!