Problems with jQuery autocomplete + AngularJS

30,623

Solution 1

Perhaps you just need to do it in an "angular way"... that is, to use a directive to set up your DOM elements and do event bindings, use a service to get your data, and use a controller to do your business logic... all while leveraging the dependency injection goodness that is Angular...

A service to get your autocomplete data...

app.factory('autoCompleteDataService', [function() {
    return {
        getSource: function() {
            //this is where you'd set up your source... could be an external source, I suppose. 'something.php'
            return ['apples', 'oranges', 'bananas'];
        }
    }
}]);

a directive to do the work of setting up the autocomplete plugin.

app.directive('autoComplete', function(autoCompleteDataService) {
    return {
        restrict: 'A',
        link: function(scope, elem, attr, ctrl) {
                    // elem is a jquery lite object if jquery is not present,
                    // but with jquery and jquery ui, it will be a full jquery object.
            elem.autocomplete({
                source: autoCompleteDataService.getSource(), //from your service
                minLength: 2
            });
        }
    };
});

And using it in your markup... notice the ng-model to set a value on the $scope with what you select.

<div ng-controller="Ctrl1">
    <input type="text" ng-model="foo" auto-complete/>
    Foo = {{foo}}
</div>

That's just the basics, but hopefully that helps.

Solution 2

I had to do a bit more work to get this working using an $http service.

The service:

app.factory("AutoCompleteService", ["$http", function ($http) {
    return {
        search: function (term) {
            return $http.get("http://YourServiceUrl.com/" + term).then(function (response) {
                return response.data;
            });
        }
    };
}]);

The directive:

app.directive("autocomplete", ["AutoCompleteService", function (AutoCompleteService) {
    return {
        restrict: "A",
        link: function (scope, elem, attr, ctrl) {
            elem.autocomplete({
                source: function (searchTerm, response) {
                    AutoCompleteService.search(searchTerm.term).then(function (autocompleteResults) {
                        response($.map(autocompleteResults, function (autocompleteResult) {
                            return {
                                label: autocompleteResult.YourDisplayProperty,
                                value: autocompleteResult 
                            }
                        }))
                    });
                },
                minLength: 3,
                select: function (event, selectedItem) {
                    // Do something with the selected item, e.g. 
                    scope.yourObject= selectedItem.item.value;
                    scope.$apply();
                    event.preventDefault();
                }
            });
        }
    };
}]);

The html:

<input ng-model="YourObject" autocomplete />
Share:
30,623

Related videos on Youtube

Flavio CF Oliveira
Author by

Flavio CF Oliveira

Updated on July 09, 2022

Comments

  • Flavio CF Oliveira
    Flavio CF Oliveira almost 2 years

    i'm using AjgularJS on my page and want to add a field to use autocomplete from jqueryui and the autocomplete does not fires the ajax call.

    i've tested the script on a page without angular (ng-app and ng-controller) and it works well, but when i put the script on a page with angularjs it stops working.

    any idea?

    jquery script:

    $(function () {
    
        $('#txtProduct').autocomplete({
            source: function (request, response) {
    
                alert(request.term);
    
            },
            minLength: 3,
            select: function (event, ui) {
    
            }
        });
    
    });
    
    • interesting note: when i call the script on Chrome inspector the autocomplete starts working!!!
    • Versions: AngularJS: 1.0.2 - JqueryUI: 1.9.0

    CONCLUSION: The autocomplete widget from jQueryUI must be initializes from inside a custom directive of AngularJS as the example:

    Markup

    <div ng-app="TestApp">
        <h2>index</h2>
        <div ng-controller="TestCtrl">
    
            <input type="text" auto-complete>ddd</input>
    
        </div>
    </div>
    

    Angular script

    <script type="text/javascript">
    
        var app = angular.module('TestApp', []);
    
        function TestCtrl($scope) { }
    
        app.directive('autoComplete', function () {
            return function postLink(scope, iElement, iAttrs) {
    
                $(function () {
                    $(iElement).autocomplete({
                        source: function (req, resp) {
                            alert(req.term);
                        }
                    });
                });
    
            }
        });
    
    </script>
    
    • Sachin Prasad
      Sachin Prasad over 11 years
      You should try loading them in $(document).ready(); Also check for errors in firebug console.
    • mccannf
      mccannf over 11 years
      Agreed - you will need to check for conflicts between AngularJS and JQuery. There don't appear to be any in a simple test: jsfiddle.net/mccannf/w69Wt
    • Tosh
      Tosh over 11 years
      It may not be relevant from the problem you are seeing, but I think you should be use jquery inside the custom directive (link function).
    • Flavio CF Oliveira
      Flavio CF Oliveira over 11 years
      Thanks guys, the solution that work for me is the suggested by tosh, creating a custom directive for that!!!
  • Ash McConnell
    Ash McConnell about 11 years
    The elem.autocomplete needs to be $(elem).autocomplete
  • Ben Lesh
    Ben Lesh about 11 years
    @AshMcConnell: if jQuery is registered on the page before Angular, the elem argument to the link function is a jQuery object already. So no $() required. ;) Angular is slick like that.
  • Ash McConnell
    Ash McConnell about 11 years
    thanks! I didn't know that, I'll check the import order when I get back to work tomorrow! (It's just the order of imports you mean?)
  • Ben Lesh
    Ben Lesh about 11 years
    Correct, as long as your <script src="jquery.js"></script> is before your <script src="angular.js"></script>, it should use jQuery objects rather than jqLite objects for Elements within Angular.
  • Aldo
    Aldo almost 11 years
    Worked perfect. Thanks !
  • sar
    sar about 10 years
    I am getting following error 'Error: autocompleteResult is not defined'
  • Jason
    Jason about 10 years
    Is your service returning any information? For example, in my service I'm returning response.data. If you are also returning that, make sure your service call is also returning data.
  • jsduniya
    jsduniya about 10 years
    @Jason: can u please show me the format for json return data from get method.
  • Jason
    Jason about 10 years
    @Siddesh Bhalke: Any arbitrary json can be returned by your service. In this example, autocompleteResults is an array of objects each of which has a property named 'YourDisplayProperty'.
  • Zeeshan
    Zeeshan almost 10 years
    How to put <input type="text" ng-model="foo" auto-complete/> in Jade Template? It sets auto-complete="auto-complete"
  • Mariusz.W
    Mariusz.W about 9 years
    I had a problem that the list was disappearing before anyone could click anything. I fixed that with the solution by corolla from this question: stackoverflow.com/questions/6043506/…
  • Joseph Nields
    Joseph Nields about 8 years
    I've found that I need to update ngModel on the "select" event
  • Cristian Martinez
    Cristian Martinez over 6 years
    Use: if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') { $scope.$apply(); }