Show loading animation for slow script using AngularJS?

The problem is that as long as Javascript is executing, the UI gets no chance to update. Even if you present a spinner before filtering, it will appear “frozen” as long as Angular is busy.

A way to overcome this is to filter in chunks and, if more data are available, filter again after a small $timeout. The timeout gives the UI thread a chance to run and display changes and animations.

A fiddle demonstrating the principle is here.

It does not use Angular’s filters (they are synchronous). Instead it filters the data array with the following function:

function filter() {
    var i=0, filtered = [];
    innerFilter();

    function innerFilter() {
        var counter;
        for( counter=0; i < $scope.data.length && counter < 5; counter++, i++ ) {
            /////////////////////////////////////////////////////////
            // REAL FILTER LOGIC; BETTER SPLIT TO ANOTHER FUNCTION //
            if( $scope.data[i].indexOf($scope.filter) >= 0 ) {
                filtered.push($scope.data[i]);
            }
            /////////////////////////////////////////////////////////
        }
        if( i === $scope.data.length ) {
            $scope.filteredData = filtered;
            $scope.filtering = false;
        }
        else {
            $timeout(innerFilter, 10);
        }
    }
}

It requires 2 support variables: $scope.filtering is true when the filter is active, giving us the chance to display the spinner and disable the input; $scope.filteredData receives the result of the filter.

There are 3 hidden parameters:

  • the chunk size (counter < 5) is small on purpose to demonstrate the effect
  • the timeout delay ($timeout(innerFilter, 10)) should be small, but enough to give the UI thread some time to be responsive
  • the actual filter logic, which should probably be a callback in real life scenarios.

This is only a proof of concept; I would suggest refactoring it (to a directive probably) for real use.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)