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.