is there a post render callback for Angular JS directive?

ghz 1years ago ⋅ 4145 views

Question

I 've just gotten my directive to pull in a template to append to its element like this:

# CoffeeScript
.directive 'dashboardTable', ->
  controller: lineItemIndexCtrl
  templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
  (scope, element, attrs) ->
    element.parent('table#line_items').dataTable()
    console.log 'Just to make sure this is run'

# HTML
<table id="line_items">
    <tbody dashboard-table>
    </tbody>
</table>

I am also using a jQuery Plugin called DataTables. The general usage of it is like this: $('table#some_id').dataTable(). You can pass in the JSON data into the dataTable() call to supply the table data OR you can have the data already on the page and it will do the rest.. I am doing the latter, having the rows already on the HTML page.

But the problem is that I have to call the dataTable() on the table#line_items AFTER DOM ready. My directive above calls the dataTable() method BEFORE the template is appended to the directive's element. Is there a way that I can call functions AFTER the append?

Thank you for your help!

UPDATE 1 after Andy's answer:

I want to make sure that the link method does only get called AFTER everything is on the page so I altered the directive for a little test:

# CoffeeScript
#angular.module(...)
.directive 'dashboardTable', ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        element.find('#sayboo').html('boo')

      controller: lineItemIndexCtrl
      template: "<div id='sayboo'></div>"

    }

And I do indeed see "boo" in the div#sayboo.

Then I try my jquery datatable call

.directive 'dashboardTable',  ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        element.parent('table').dataTable() # NEW LINE

      controller: lineItemIndexCtrl
      templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
    }

No luck there

Then I try adding a time out :

.directive 'dashboardTable', ($timeout) ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        $timeout -> # NEW LINE
          element.parent('table').dataTable()
        ,5000
      controller: lineItemIndexCtrl
      templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
    }

And that works. So I wonder what goes wrong in the non-timer version of the code?


Answer

If the second parameter, "delay" is not provided, the default behaviour is to execute the function after the DOM has completed rendering. So instead of setTimeout, use $timeout:

$timeout(function () {
    //DOM has finished rendering
});