Responsive long running browser service

A long-running service in the browser that does not freeze the UI.

by Nikos Paraskevopoulos

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl">
    <p>
        A list of 1000 random 6-digit numbers is created. Enter some digits in the text box to filter only those numbers that contain the sequence in the text box. A spinner is displayed and the text box is disabled while filtering.
    </p>
    <p>
        Please note that because the random generation is quite naive, duplicates may occur. In this case Angular complains; just press "Run" again to generate another sequence.
    </p>
    <input type="text" ng-model="filter" ng-disabled="filtering" />
    <img width="10" height="10" title="" alt="" src="data:image/gif;base64,R0lGODlhCgAKALMIAP7+/uDg4MzMzL29vbCwsJycnI2NjXx8fP4BAgAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBwAIACwAAAAACgAKAAAELxChUM4pQaJh+xnTYRwAwB2UAYxGwFUBEFiqt1rxXA0Bu2KWQUmE2niCGooFI4kAACH5BAUHAAgALAEAAQAIAAgAAAQaEElkJiKhCklQsMiBDCBIitbXIZsRrFIFSBEAIfkEBQcACAAsAQABAAgACAAABB8QIUOOlAKMMtHJFSJIgWGQ6GQEmEeI1lkMwHgdxIlEACH5BAUHAAgALAIAAQAGAAgAAAQZEI2JkAlgGBkCEhUCVMCIHCHoDdYABJtERQAh+QQFBwAIACwCAAEABgAIAAAEFxAdhIwUCIiJCDEEII1k9nnUIYhblSIRACH5BAUHAAgALAIAAQAGAAgAAAQZEKFDihwSEIGMGIYkDpjYDUIoEMAlFcQhRQAh+QQFBwAIACwBAAEACAAIAAAEGhBJdIyZKOSBUQHApSHWIVVXRoJFN2ijVGIRACH5BAUHAAgALAEAAQAIAAgAAAQgEEl5jjQCBVEMGleAdJUkAMMAZEhlFJr3Ia8gCnI5IREAIfkEBQcACAAsAQACAAgABgAABBkQHQTAOMeYgrpAA8BNiPBJSGGVXaphIYBGADs=" ng-if="filtering" />
    <ul>
        <li ng-repeat="x in filteredData">{{x}}</li>
    </ul>
</div>

JavaScript

var app = angular.module("app",[]);

app.controller("Ctrl", function($scope, $timeout) {
    $scope.filter = "";
    $scope.filtering = false;
    
    $scope.data = (function() {
        // create some dummy data
        var ret = [], i;
        for( i=0; i < 1000; i++ ) {
            ret.push(""+parseInt(Math.random()*1000000));
        }
        return ret;
    })();
    
    $scope.filteredData = null;
    
    $scope.$watch("filter", function(newval) {
        if( !newval ) {
            $scope.filteredData = [];
        }
        else {
            $scope.filtering = true;
            filter();
        }
    });
    
    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);
            }
        }
    }
});