61

I'm trying to write an autocomplete directive that fetches data from the server using an $http request (without using any external plugins or scripts). Currently it works only with static data. Now, I know that I need to insert my $http request into the source: of the directive, but I can't find any good documentation on the subject.

http request

$http.post($scope.url, { "command": "list category() names"}). 
            success(function(data, status) {
                $scope.status = status;
                $scope.names = data;    
            })
            .
            error(function(data, status) {
                $scope.data = data || "Request failed";
                $scope.status = status;   
            });

Directive

app.directive('autoComplete', function($timeout) {
    return function(scope, iElement, iAttrs) {
            iElement.autocomplete({
                source: scope[iAttrs.uiItems],
                select: function() {
                    $timeout(function() {
                      iElement.trigger('input');
                    }, 0);
                }
            });
        };
    });

View

<input auto-complete ui-items="names" ng-init="manualcat='no category entered'" ng-model="manualcat"> 

So, how do I piece this all together correctly the Angular way?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Gidon
  • 3,490
  • 7
  • 23
  • 31
  • Can you provide the full example source code? I just want to know at what time you actually make the HTTP call. Thanks in advance. – Matthias Jun 28 '15 at 08:36
  • have you found the solution? i'm facing the same problem, seems like $scope.names is empty when directive is loaded, the ajax call is left behind – Agung Setiawan Nov 23 '15 at 10:36

5 Answers5

45

I made an autocomplete directive and uploaded it to GitHub. It should also be able to handle data from an HTTP-Request.

Here's the demo: http://justgoscha.github.io/allmighty-autocomplete/ And here the documentation and repository: https://github.com/JustGoscha/allmighty-autocomplete

So basically you have to return a promise when you want to get data from an HTTP request, that gets resolved when the data is loaded. Therefore you have to inject the $qservice/directive/controller where you issue your HTTP Request.

Example:

function getMyHttpData(){
  var deferred = $q.defer();
  $http.jsonp(request).success(function(data){
    // the promise gets resolved with the data from HTTP
    deferred.resolve(data);
  });
  // return the promise
  return deferred.promise;
}

I hope this helps.

justGoscha
  • 24,085
  • 15
  • 50
  • 61
  • This is throwing an error for me on the template html file that you included in the download. Is this required? If so you may want to make that obvious in the documentation – Metropolis Jun 11 '14 at 01:44
  • 4
    Does it require all data to be fetched to memory? What if I have 10M+ variants? :) – tuxSlayer Sep 11 '14 at 12:17
  • @tuxSlayer download first 20 what match your criteria – Artiom Sep 22 '14 at 18:05
  • 1
    any attribute to limit the no of results? – Ashish Gupta Oct 30 '14 at 16:42
  • 1
    Does this have a timeout you can set, for example... do an http request once you've stopped typing for 1 second? I don't want it to make a request on every key pressed... @JustGoscha – dotnethaggis Mar 09 '15 at 08:55
  • @JustGoscha please help me for this question : http://stackoverflow.com/questions/31578775/how-to-have-dynamic-ng-model-in-angularjs-directive – Emil Jul 25 '15 at 05:35
  • I was able to install it. But the select options / matching results are showing behind the next list item. Any way to move them to front? I am looking for an experience similar to NGAutcomplete. – techwestcoastsfosea Dec 08 '15 at 05:41
  • @justgoscha , what's the best way to add a spinner (loading animation ) to this? – gdubs Jun 10 '16 at 15:50
37

Use angular-ui-bootstrap's typehead.

It had great support for $http and promises. Also, it doesn't include any JQuery at all, pure AngularJS.

(I always prefer using existing libraries and if they are missing something to open an issue or pull request, much better then creating your own again)

Urigo
  • 3,175
  • 21
  • 27
17

You need to write a controller with ng-change function in scope. In ng-change callback you do a call to server and update completions. Here is a stub (without $http as this is a plunk):

HTML

<!doctype html>
<html ng-app="plunker">
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
        <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.4.0.js"></script>
        <script src="example.js"></script>
        <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
    </head>
    <body>
        <div class='container-fluid' ng-controller="TypeaheadCtrl">
            <pre>Model: {{selected| json}}</pre>
            <pre>{{states}}</pre>
            <input type="text" ng-change="onedit()" ng-model="selected" typeahead="state for state in states | filter:$viewValue">
        </div>
    </body>
</html>

JS

angular.module('plunker', ['ui.bootstrap']);

function TypeaheadCtrl($scope) {
  $scope.selected = undefined;
  $scope.states = [];

  $scope.onedit = function(){
    $scope.states = [];

    for(var i = 0; i < Math.floor((Math.random()*10)+1); i++){
      var value = "";

      for(var j = 0; j < i; j++){
        value += j;
      }
      $scope.states.push(value);
    }
  }
}
madhead
  • 31,729
  • 16
  • 153
  • 201
  • 2
    Thanks for the answer madhead. But, like I said in my question, I'm trying to avoid using any external scripts. In your answer you are using the angular-ui bootstrap script. I'm looking for a pure angular solution. Cheers, Gidon – Gidon Aug 28 '13 at 06:35
  • 3
    I'm using angular-ui for `typeahead` directive (autocomplete itself). – madhead Aug 28 '13 at 06:46
6

the easiest way to do that in angular or angularjs without external modules or directives is using list and datalist HTML5. You just get a json and use ng-repeat for feeding the options in datalist. The json you can fetch it from ajax.

in this example:

  • ctrl.query is the query that you enter when you type.
  • ctrl.msg is the message that is showing in the placeholder
  • ctrl.dataList is the json fetched

then you can add filters and orderby in the ng-reapet

!! list and datalist id must have the same name !!

 <input type="text" list="autocompleList" ng-model="ctrl.query" placeholder={{ctrl.msg}}>
<datalist id="autocompleList">
        <option ng-repeat="Ids in ctrl.dataList value={{Ids}}  >
</datalist>

UPDATE : is native HTML5 but be carreful with the type browser and version. check it out : https://caniuse.com/#search=datalist.

londox
  • 306
  • 2
  • 7
0

I found this link helpful

$scope.loadSkillTags = function (query) {
var data = {qData: query};
   return SkillService.querySkills(data).then(function(response) {
   return response.data;
  });
 };
Joe B
  • 738
  • 7
  • 28