Running code after a digest cycle in AngularJS

Posted by ryansouthgate on 2 Sep 2015

While working with AngularJS and Highcharts, I had the need of running code after a digest cycle in AngularJS.

The reason for this:
I have 4 charts on a page, the X-Axis of all charts needs to be “synced” across charts – all charts need the same X-Axis “categories”. Each one of these charts sits in a container with some input fields – these input fields can be edited and then each container can be updated – via a call to a WebApi back-end.

When the results come back, I draw the returned values on to the chart. If these new results have changed the number of categories on the X-Axis (has more or less than before) then I need to go and change the other charts too – to ensure they are “synced” up.

I’m using AngularJS directives (a very nice way of creating re-usable components) to draw the chart. Inside these directives I have watches – to you know – watch for changes from the WebApi.

Now, anyone of the Containers can change at any time (by the user), using the directive I can change the “updated container’s” chart to the new values. I can even go on to mess about with every other chart on the page and ensure the X-Axis are synced. I wrote some code for this and started to get into a web of trouble. The code needed to update all charts after one had been updated. The ever increasing number of checks that were occurring in my code got me worried, eventually I decided – this is not the best way to do this! Essentially I needed to ensure I had all the data (after all watches had completed – the digest cycle) and then go off and update the charts X-Axis.

A quick “google” posted a few suggestions:

1 – $$postDigest()

Passing a function to $$postDigest, will run the function after angular has finished the digest cycle – duh!

Code:

$scope.$$postDigest(function () { 
    console.log("this happens after the digest cycle!!"); 
});

This works and is great. However………….anything marked with $$ in angular is considered “private”. So you probably want to be careful if choosing this method. The angular team might make changes to this interface and therefore your code might break on upgrading to a later version. So be mindful of this!!

2 – $timeout()

On first look, you’d be forgiven if you thought that this was simple a way for running a chunk of code after a fixed amount of time (I did too!).
$timeout can also be used to ensure some code runs after the digest cycle.

As $timeout is a “public interface”, the angular team are less likely to make breaking changes to it. Therefore it “should” be safer and more consistent.

Set the $timeout to 0 seconds (run immediately – after the digest cycle). In my case I need to set the “invokeApply” parameter to false. Setting this to false ensures that another digest cycle is not executed after the current one.
As my need is to change chart metadata – (non-angular model stuff) I set this to false. If you’re going to be changing view/model values, then you’ll want to set this to true.

Code:

// Timeout of 0 seconds (ensures running the following code happens after the digest cycle 
// False - skips dirty checking - digest cycle 
$timeout(function () { 
   console.log("timeout should run after the the digest!!"); 
}, 0, false);

There you have it. Guaranteed – running code after a digest cycle!



comments powered by Disqus