Strange! JQuery Datatables, ngRepeat and $http

2,136 views
Skip to first unread message

Makarand Bhatamrekar

unread,
Nov 29, 2013, 11:57:44 AM11/29/13
to ang...@googlegroups.com

I have been struggling to get these three things working together, below is the link to the working code in plunkr


but as soon as I try to get the data from $http, it does not work at all, below is the not working plunkr


thx for the read and help!!


Makarand Bhatamrekar

unread,
Nov 29, 2013, 2:03:42 PM11/29/13
to ang...@googlegroups.com
When I try to run the code on local machine it throws me
TypeError: Cannot call method 'insertBefore' of null

guys, advise

Daniel Tabuenca

unread,
Nov 29, 2013, 2:14:01 PM11/29/13
to ang...@googlegroups.com

First let me start by saying that integrating angular with jquery datatables is not trivial, especially if you want to use angular dom as the ‘datasource’. The best way to do this is to use a javascript data source and leave all the rendering up to the datatables plugin. For more information on how to do that take a look at this page:

http://myjitjs.wordpress.com/2013/11/04/data-table-in-angular/

Regardless, let me try to answer why your code doesn’t work when you use $http.

The way you are using the datatable plugin is with dom as a datasource. This requires that by the time you call $.dataTable() the dom be already rendered:

<table class="mytable">
    <thead> 
         <tr> <th>counting</th> </tr> 
    </thead>
    <tbody> 
        <!-- ngRepeat: data in datas --> 
        <tr ng-repeat="data in datas" class="ng-scope"> <td class="ng-binding">Johny 1</td> </tr>
        <tr ng-repeat="data in datas" class="ng-scope"> <td class="ng-binding">Johny 2</td> </tr>
        <tr ng-repeat="data in datas" class="ng-scope"> <td class="ng-binding">Johny 3</td> </tr> 
     </tbody>
 </table>

As you’ve already found out when you had to wrap the $.dataTable() call in a $timeout(), it can be a little tricky to ensure that the dom has rendered before you call $.dataTable()

For example in your static example:

     link : function(scope, element, attrs, ctrl) {
         scope.datas = ["one", "two", "three"]
         // Doesn't work, shows an empty table:
         // $('.mytable', element).dataTable()   
         // But this does:
        $timeout(function() { $('.mytable', element).dataTable(); 
        }, 0)
      }

The reason $('.mytable', element).datTable() does not work is because the dom hasn’t been rendered yet. At this point, you’ve set scope.datas = ["one", "two", "three"] but the watch (setup by ng-repeat) that actually renders that out to the dom won’t execute until the next $digest() cycle, which won’t hapen until after the link function returns.

By setting a $timeout you are forcing the execution of dataTable() until after the current thread is done running, at which point angular should have finished it’s $digest() and everything should have been rendered, so it works.

In the case where you use $http we face the same issue, in that the dom must have been rendered before you call dataTable(). However, in this case it’s not simply sufficient to set a $timeout because even after the current thread finishes executing the $http() call might not have yet returned, and so we might still not have the dom that we need.

In this case we have to make sure the dataTable() is called after the $http call returns:

scope.datas.then(function(){
  $timeout(function() { 
    $('.mytable', element).dataTable(); 
  }, 0);
})

Notice we still have to use $timeout since even though at this point we know the data has been returned from the server, we don’t know for sure if it has been rendered yet.

Hopefully this clears up why things were not working as expected when you were using $http. However, like I pointed out, you will probably find many additional issues integrating dataTables in this way. So I en courage you to read that link I posted on the top.

Makarand Bhatamrekar

unread,
Nov 30, 2013, 4:11:34 AM11/30/13
to ang...@googlegroups.com
Hi Daniel

Thank you so much for sharing a very detailed experience as well as the contribution, definatley it will save tons of time for anybody who goes to the path of angular datatables. I further tried to work to the workarounds, where list works, but edit record, it again tries to run the script and fails, so as mentioned, it does not make sense to use the Angular in the way tried below.
I will give a shot to your example on github and let know

Thanks a ton!! This story has dragged me for more than a day now..

Makarand Bhatamrekar

unread,
Dec 10, 2013, 10:26:00 AM12/10/13
to ang...@googlegroups.com
Hi Daniel

I tried the plugin developed on github, but it seems too complicated and it will take additional efforts to implement server side paging /styling..found an alternative, which keeps the jquery datatables intact yet integrates perfectly with the AngularJS controllers, pls refer to

http://jsfiddle.net/TNy3w/2/
 
I tested the above example, it works awesome with $rest data as well as if you need to use angularJS stuff,  needto add folliwng to the controller

 $scope.options.fnCreatedRow = function( nRow, aData, iDataIndex ) {
        $compile(nRow)($scope);
    }

thanks
Reply all
Reply to author
Forward
0 new messages