Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a $resource to populate Angular UI Bootstrap typeahead

I am trying to get Angular UI bootstraps typeahead working with a REST resource I have set up. But I am not sure how to get it working with it's asynchronous nature.

At the moment I have adapted the example given by Angular UI Bootstrap.

so my html looks like so, calling getLibs() to get the list for the typeahead dropdown.

<div class='container-fluid' ng-controller="TypeaheadCtrl">
    <pre>Model: {{selected| json}}</pre>
    <input type="text"  typeahead="lib.name for lib in getLibs($viewValue)" active='active' ng-model="selected" typeahead-min-length='3' >
</div>

my resource looks like so:

angular.module('LibraryLookupService', ['ngResource']).factory('Library', 
    function($resource){
        return $resource(   "../../api/seq/library/?name__icontains=:searchStr" , {} , 
        {   'get':    {method:'GET'},
            'query':  {method:'GET', params: {} ,  isArray:false },
        }
    )
}

);

my controller looks like so (I am guessing it is here I am doing something incorrect):

function TypeaheadCtrl($scope , Library){

    $scope.selected = undefined;
    $scope.active = undefined ;

    $scope.libs = [{name:'initial'} , {name:"values"}];

    $scope.getLibs = function(viewValue){
        console.log("value:", viewValue);
        if (viewValue.length > 3 ) { 
            var return_vals =  Library.query({searchStr:viewValue},  function() {
                $scope.libs = return_vals.objects ; 
                console.log("here", $scope.libs) ; 
                }) ;
            }
        return $scope.libs
    }
}

So as I understand it, the typeahead menu is being populated from the return value of the getLibs() function. When getLibs() is called it is querying the REST interface, but initially an empty value is returned. This is being populated by the function supplied to the Library.query() method, and this is done after the data is returned from the REST request.

This means basically that the menu is being updated one keypress later than what I want. I type '3456' and it gets populated with results of a '345' query to the REST interface.

How do I get the menu to update when the response is returned from the Library.query() function? Am I going about this correctly?

like image 919
wobbily_col Avatar asked Apr 10 '13 14:04

wobbily_col


2 Answers

I solved it this way:

My factory:

angular.module('frontendApp')
  .factory('PersonService', function($resource) {
    // Service logic
    // ...

    return $resource(APP_CONFIG.prefixURLRest + '/person', {
      //id: '@id'
    }, {
      search: {
        method: 'POST',
        isArray: true
      }
    });

  });

My controller

...
$scope.searchTypeAhead = function(name) {
  var person = {
    'name': name
  };

  return PersonService.search(person)
    .$promise.then(function(response) {
      return response;
    });
};
like image 191
Joander Vieira Cândido Avatar answered Sep 21 '22 12:09

Joander Vieira Cândido


The typeahead directive from http://angular-ui.github.io/bootstrap/ relays on the promise API ($q) to handle asynchronous suggestions. The trouble with $resource is that is used to lack support for promises (it was added only recently in the unstable branch). So you've got 2 solutions here:

1) relay on $http that works with promises (IMO $http should be more than enough for most auto-complete cases). 2) Switch to the latest unstable version of AngularJS and work with promises.

The purpose of the $resource is to work with the full set of HTTP verbs to target RESTful endpoints. If you want to just query data you might be better off using $http for this purpose anyway.

There is a similar question about typeahead with an answer that covers of its usage with $http: How to tie angular-ui's typeahead with a server via $http for server side optimization?

like image 27
pkozlowski.opensource Avatar answered Sep 21 '22 12:09

pkozlowski.opensource