What is the best approach for autocomplete in AngularJS?

33,264 views
Skip to first unread message

Stein Gran

unread,
Oct 17, 2012, 4:18:10 AM10/17/12
to ang...@googlegroups.com
Hi,

What is the best approach for autocomplete in AngularJS? I have a web application built with AngularJS, and this application has an input field for searching. For this field I need some sort of autocomplete functionality, the data source for the autocomplete is a MVC4 Web API (remote datasource). Something that looks and behaves like the autocomplete on www.google.com would have been nice.

I have researched this a bit, and have tried the following approaches:

1. jQuery UI Autocomplete. But this one does not play nicely together with AngularJS, I get an error message saying that .autocomplete does not exist for the element I'm trying to attach it to. But the look and feel of the jQuery UI autocomplete is very nice and clean, and just what I want.
2. AngularUI Select2 directive. But this looks and feels like a combobox, not a search autocomplete feature
3. AngularJS Autocomplete sample as listed on the JSFiddle Examples page (https://github.com/angular/angular.js/wiki/JSFiddle-Examples): http://jsfiddle.net/ZguhP/. This would have been excellent, but it does not support using key up and key down to select an autocomplete suggestion. Otherwise this is perfect.
4. AngularJS custom directive based on samples found in this group and elseewhere:

directive('cxAutocomplete', function () {
        return {
            restrict: 'E',
            replace: true,
            transclude: true,
            template: '<input id="searchbox" type="search" autofocus="true" size="50" spellcheck="true" ng-model="coxitoSearchParameter"   />',
            link: function (scope, element, attrs) {
                scope.$watch(attrs.list, function (value) {
                    element.autocomplete({
                        source: value,
                        select: function (event, ui) {
                            scope[attrs.selection] = ui.item.value;
                            scope.$apply();
                        }
                    });
                });
            }
        };
    })

Calling this directive in HTML:
<cx-autocomplete selection="name" list="doGetAutocomplete" />

The doGetAutocomplete() method:
$scope.doGetAutocomplete = function (request, response) {
        $scope.autocompleteResult = $scope.coxitoautocomplete.get({ MaxSuggestions: '5', UserQuery: $scope.coxitoSearchParameter }, $scope.doneAutocomplete(response));
 };

I added a callback method ($scope.doneAutocomplete(response)) in the above function, with the intention of it being called when the data arrived from the remote datasource, but this callback function seems to be called immediately instead of waiting until data is returned. If this callback function had been called when I want it to be called then this solution would have worked just fine.
But the result of this directive and these functions is nothing, since it does not wait until data arrives from the remote datasource. 

The $scope.doneAutocomplete(response) callback function looks like this, this is where I assign data with the response callback function:
$scope.doneAutocomplete = function (response) {
        response($scope.autocompleteResult.Suggestions);
        $scope.$apply();
};


Does anyone see what is wrong with the callback method here, why is it not called when the data is returned?  Sorry that I cannot create a JSFiddle for this, since my datasource is not externally accessible.


So that's the four approaches I have tried. Note that I am not a Javascript expert, so I may have missed something obvious somewhere.
What is the best practice for implementing an autocomplete with a remote datasource in AngularJS?

Thanks for your help.

Best,
Stein J. Gran



PS: I sent this message to this Google group yesterday as well, but since I cannot see it in the group I post it again. Sorry for any double-posting.
Message has been deleted

Stein Gran

unread,
Oct 18, 2012, 4:37:37 AM10/18/12
to ang...@googlegroups.com
After reading this post I figured it out: https://groups.google.com/forum/?fromgroups=#!topic/angular/FZHa7BCnFGs

Changed my doGetAutocomplete function to this, and everything works:

$scope.doGetAutocomplete = function (request, response) {
        $scope.coxitoautocomplete.get(
            { MaxSuggestions: '5', UserQuery: $scope.coxitoSearchParameter },
            function (data) { // success
                response(data.Suggestions);
            },
            function (data) { // failure
                console.log("Add error handling");
            }
        );
    };

Best,
Stein J. Gran

Erlend Strømsvik

unread,
Nov 6, 2013, 5:57:35 AM11/6/13
to ang...@googlegroups.com
Old thread and all... 
But since this was one of the first posts I found when searching for AutoComplete in AngularJS, I'm going to post what we did, just for future reference :)

We fetched a custom build for UI Bootstrap from http://angular-ui.github.io/bootstrap/. Only checked off Typeahead. 
UI Bootstrap depends on Bootstrap CSS which if HUGE... 

From Bootstrap CSS we extracted only these lines and included those in our own styles.css:
/* Typeahead stuff
----------------------------*/
.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  display: none;
  float: left;
  min-width: 160px;
  padding: 5px 0;
  margin: 2px 0 0;
  font-size: 14px;
  list-style: none;
  background-color: #ffffff;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 4px;
  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  background-clip: padding-box;
}
.dropdown-menu li a {
  display: block;
  padding: 3px 20px;
  color: #333333;
  white-space: nowrap;
}
.dropdown-menu .active a, .dropdown-menu .active a:hover, .dropdown-menu .active a:focus {
  color: #ffffff;
  text-decoration: none;
  background-color: #428bca;
  outline: 0;
}

Template looks like this:
<input type="text" typeahead-wait-ms="300" typeahead="k for k in getList($viewValue)">

Controller:
    $scope.getList = function(term) {
      return messageService.getPromiseList(term);
    }

Service:
      getPromiseList: function(term) {
        var request  = 'http://fetch.data.com/service?term=' + term;
        return $http.get(request).then(function(response) {
            // have to loop through result because it's key => value
            var _list = [];
            for(var key in response.data.d) {
              _list.push(response.data.d[key]);
            }
            return _list;
          });
      },

Works with the browsers we have tested and on mobile devices. Support key up/down. And for our part we like the looks of it.

D. Zen

unread,
Feb 19, 2014, 3:35:32 PM2/19/14
to ang...@googlegroups.com
This topic came up recently at http://www.meetup.com/AngularJS-NYC/events/165587672/

I looked briefly at http://angular-ui.github.io/bootstrap/#/typeahead but wound up using a variation of 


It's not the lightest weight solution. It requires JQuery-UI. 
I used JQuery and replaced source: with a $.ajax request to service that returned JSON. And, my success: did a $.map to put the data in the correct format.

Pawel Kozlowski

unread,
Feb 19, 2014, 3:41:38 PM2/19/14
to ang...@googlegroups.com
Hi Daniel,

On Wed, Feb 19, 2014 at 9:35 PM, D. Zen <dan...@gmail.com> wrote:
> I looked briefly at http://angular-ui.github.io/bootstrap/#/typeahead but
> wound up using a variation of
>
> http://jsfiddle.net/sebmade/swfjT/

Out of curiosity, did you hit any particular roadblocks with
http://angular-ui.github.io/bootstrap/#/typeahead?
Would like to improve if there are particular points to address.

Cheers,
Pawel


--
AngularJS book:
http://www.packtpub.com/angularjs-web-application-development/book
Looking for bootstrap-based widget library for AngularJS?
http://angular-ui.github.com/bootstrap/
Reply all
Reply to author
Forward
0 new messages