In my last two posts, I experimented with building the Sieve of Eratosthenes in JavaScript. I wanted to provide a visualization of the algorithm so I used CSS animations to indicate changes in state. At first I did this using timeouts to show the execution after a delay, which meant my code was not using recursion as you might expect from the algorithm. When I moved to keeping things isolated in a queue of states and then iterating over those states, the algorithm looked better, but AngularJS did not know that my states were connected and could not apply the proper classes to display the animations. I’ve been refactoring this for a bit and have a good solution now which preserves the animations and allows the original algorithm to run without timeout callbacks.

The way it works is by exposing an AngularJS service which stores the states. When a state change occurs, you call into this service and store that state. The service then invokes its own callback thread to iterate over the states and set the “current state” to the first item off the queue. Inside your controller you store a reference to the current state, and then use that reference inside your HTML template. As the service updates the states, you’ll see the changes reflected in your template.

In order to take advantage of AngularJS dirty checking, the Algorithm intelligently copies objects into the state queue. If the object is an array of objects, it makes sure to copy each key of the object, rather than just the entire object. This allows AngularJS to know that the object has changed and apply the CSS classes to show animation. You can see this in the function

1
addArrayItemToWorldState
. Also, note that this service has no clue what items I am putting into the state. You push the items into the state queue and then know that
1
the_state
will have the net one in the sequence ready for you in your template.

A sample calling pattern might be:

1
2
3
4
5
6
7
8
9
10
11
12
13
var mod = angular.module( "MyModule" , [ 'AnimateAlgorithms' ] );

mod.controller( "MyAlgorithmCtrl", [ '$scope', 'Algorithm', 
  function( $scope, Algorithm ) {
    $scope.start = function() {
      $scope.state = Algorithm.the_state;
      $scope.animate( 250 ); // Iterate over 250 ms, starting two seconds after this is called
      $scope.save( { "p" : $scope.p, "numbers": $scope.numbers } );
      $scope.runLongCalculation();
      $scope.save( { "p" : $scope.p, "numbers": $scope.numbers } );                 
  }

} ] );

Your template might look like this (in HAML):

You can see this running here and get the code on GitHub.