Question

My AngularJS controller is calling an API to get a list of members. The API can be queried with multiple filters, like age range, name search, zipcode, etc.

What I am trying to accomplish is to make the user feel like the search is really fast. So while the user is filtering, I am $watch'ing the filters for changes. When a filter changes I immediately do a new search API call, instead of waiting for the user to click "search".

The idea is that when the user finishes filtering and clicks "search", the system should already be finished searching and can just output the search results.

The problem: When a user clicks "search" and the publish() function is called, I have to make sure that no API search is currently ongoing and if one is, wait for it to finish. I then publish the search results from the hidden memberslist.temp to the visible memberslist.members.

// Current code works, except the publish function. See the TODO:

app.controller('SearchCtrl', ['$scope', 'Restangular', '$timeout', function($scope, Restangular, $timeout) {

    // Pushes prefetched search results over to the visible search results
    // TODO: Check if search is ongoing...
    $scope.publish = function() {
        $scope.memberslist.members = $scope.memberslist.temp;
    };

    // Watch filters for changes
    var searchTimer    = false;
    var previousSearch = [$scope.name, $scope.minAge, $scope.maxAge];

    $scope.$watch('[name, minAge, maxAge]', function(newVal, oldVal, scope){
        if (searchTimer) {
            $timeout.cancel(searchTimer);
        }  

        // Do search only after the user has stopped typing for 400 ms
        searchTimer = $timeout(function(){
            if (!_.isEqual(newVal, previousSearch)) {
                previousSearch = newVal;
                scope.search();
            }
        }, 400);
    }, true);

    $scope.search = function() {
        var query_params = {
            name:        $scope.name, 
            price_min:   $scope.minAge,
            price_max:   $scope.maxAge
        };

        Restangular.all('members').getList(query_params)
            .then(function(members){
                $scope.memberslist.temp = members;
            });
    };
}]);

My first thought was to set a variable like isSearching = true, then set that back to false once the search call returns it's results. Can't seem to get it to work though.

Was it helpful?

Solution

Perhaps something like:

$scope.$watch('!is_searching && publishing', function(newVal){
  if (newVal) {
    $scope.memberslist.members = $scope.memberslist.temp;
    $scope.publishing = false;
  }
})

Set "is_searching" to true on the scope when the search starts, and set it to false when it is done. Set "publishing" on the scope when the search button is clicked.

That should give you the desired behavior. Publish right away if no search is running, otherwise wait until search is complete.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top