Autosuggest text box using AngularJS

Typeahead or autosuggest text boxes are one of my favorite implementations. You can do some creative things to provide some very helpful while user is entering search text in text box and you provide some advance information about suggestions. In this post I will show a very minimal implementation of autosuggest text box using AngularJS.

In nutshell any autosuggest or typeahead text box implementation needs to implement features that constitute following steps and actions.

  • Provide a text box for user to type search keyword(s)
  • Handle key press related events to get the latest text entered in text box
  • Implement a client side service that will send the entered text to server to get list of suggestions
  • Show suggestions via some dropdown kind of HTML element (div, list etc.)

HTML elements for autosuggest text box

Following snippet shows very basic implementation of autosuggest text box.


<div ng-controller="TradeSearchController" class="input-group">
    <input class="form-control" type="text" required ng-model="searchQuery.keywords" 
           ng-keyup="getSuggestions($event)" />
    <ul class="typeahead" ng-show="suggestions.length > 0">
    <li ng-repeat="suggestion in suggestions" auto-suggest-menu-item class="">
        <a href="#">{{suggestion}}</a></li>
    </ul>
    <span class="input-group-btn">
    <button class="btn-u" ng-click="search()">Go</button>
        </span>
</div>

I am using a UL element to display list of suggestions. This list is prepared by using ng-repeat directive on array of suggestions that I have got from my service. You will notice that there is a custom attribute named auto-suggest-menu-item for each li element. This has been implemented to handle mouse movement and select events on each suggestion item.

Controller for autosuggest text box

Following snippet shows controller that has been implemented for this text box.


 TradePortalApp.controller('TradeSearchController', 
     ['tradeSearchApi', '$scope', function (tradeSearchApi,$scope) {
    $scope.searchQuery = { keywords: '', filterCategory: '' };
    $scope.suggestions = [];
    $scope.getSuggestions = function (ev) {
        // Will not check untill user has entered 2 characters
        if ($scope.searchQuery.keywords.length < 2) {
            $scope.suggestions = [];
            return;
        }
        tradeSearchApi.getSugestions($scope.searchQuery.keywords).
            then(
            function(result) {
                $scope.suggestions = result;
            },
            function(result) {
                //TODO: Log this error
                $scope.suggestions = [];
            });
    }
}]);

Very straight forward implementation. The scope holds array named suggestions. This is populated by getSuggestions function on this scope. This function calls a custom AngularJS service tradeSearchApi to get promise that returns list of suggestions from service.

Custom service to get suggestions from server

Following is custom angularJS service implemented that gets suggestions list from server.


TradePortalApp.factory('tradeSearchApi', ['$http', function($http) {
var getSuggestions = function(keywords, filterCategory) {
    var action = PortalSettings.baseUrl + "api/TradeSearch/Suggestions";
    var searchQuery = { Keywords: keywords, MaxResults: -1, Filter: '' };
    return $http({ method: 'POST', url: action, data: searchQuery }).
        then(
        function (result) {
            return result.data;
        },
        function (result) {
            //TODO: Log error from this service
            return result.data;
        }
    );
}
return {
    getSugestions:getSuggestions
};
}]);

Custom attribute for suggestion items

This custom attribute auto-suggest-menu-item handles mouse events. It performs following activities.

  • Registers for mouseover event on each li item. When mouse moves over a suggestion, it adds active class to it to provide a hover affect.
  • Registers for mouseleave event. When mouse leaves that li item, it removes active class from it.
  • Registers for click event on each li item. When user selects a suggestion from list, it sets that selected name in parent scope's model.

TradePortalApp.directive('autoSuggestMenuItem', [function () {
return {
    require: '?ngModel',
    restrict:'A',
    link: function(scope, elm, attrs, ctrl) {
        if (!elm) return;
        elm.bind('mouseenter', function () {
            elm.addClass("active");
        });
        elm.bind('mouseleave', function () {
            elm.removeClass("active");
        });
        elm.bind('click', function() {
            scope.$parent.searchQuery.keywords = scope.suggestion;
            scope.$parent.suggestions = [];
            scope.$parent.$apply();
        });
    }
};
}]);

See in action

You can see this in action by visiting this page on this site. You can type ip to list of some products entered in the database. You can add some new products from Add Listing and then try to see if those appear in the suggestions or not.

Search

Social

Weather

19.3 °C / 66.7 °F

weather conditions Mist

Monthly Posts

Blog Tags