<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.4.0" data-semver="1.4.0" src="https://code.angularjs.org/1.4.0/angular.js"></script>
    <link rel="stylesheet" href="angucomplete-alt.css" />
    <link rel="stylesheet" href="style.css" />
    <script src="angucomplete-alt.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="MainCtrl">

    <h1>Example</h1>
    <div angucomplete-alt id="ex1" template-url="template" placeholder="Search countries" maxlength="50" pause="100" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" input-class="form-control form-control-small" match-class="highlight" class="ng-isolate-scope">        </div>

    <p>{{selectedCountry.title}}</p>

    <script type="text/ng-template" id="template">
      <div class="angucomplete-holder" ng-class="{'angucomplete-dropdown-visible': showDropdown}">
        <input autofocus id="{{id}}_value" name={{inputName}} ng-class="{'angucomplete-input-not-empty': notEmpty}" ng-model="searchStr" ng-disabled="disableInput" type="{{type}}" placeholder="{{placeholder}}" maxlength="{{maxlength}}" ng-focus="onFocusHandler()" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults($event)" autocapitalize="off" autocorrect="off" autocomplete="off" ng-change="inputChangeHandler(searchStr)"/>
        <div id="{{id}}_dropdown" class="angucomplete-dropdown" ng-show="showDropdown">
          <div class="angucomplete-searching" ng-show="searching" ng-bind="textSearching"></div>
          <div class="angucomplete-searching" ng-show="!searching && (!results || results.length == 0)" ng-bind="textNoResults"></div>
          <div class="angucomplete-row" ng-repeat="result in results" ng-click="selectResult(result)" ng-mouseenter="hoverRow($index)" ng-class="{'angucomplete-selected-row': $index == currentIndex}">
            <div ng-if="imageField" class="angucomplete-image-holder">
              <img ng-if="result.image && result.image != ''" ng-src="{{result.image}}" class="angucomplete-image"/>
              <div ng-if="!result.image && result.image != ''" class="angucomplete-image-default"></div>
            </div>
            <div class="angucomplete-title" ng-if="matchClass" ng-bind-html="result.title"></div>
            <div class="angucomplete-title" ng-if="!matchClass">{{ result.title }}</div>
            <div ng-if="matchClass && result.description && result.description != ''" class="angucomplete-description" ng-bind-html="result.description"></div>
            <div ng-if="!matchClass && result.description && result.description != ''" class="angucomplete-description">{{result.description}}</div>
          </div>
        </div>
      </div>
    </script>
  </body>

</html>
var app = angular.module('app', ["angucomplete-alt"]);

app.controller('MainCtrl', ['$scope', '$http',
  function MainCtrl($scope, $http) {
    $scope.remoteUrlRequestFn = function(str) {
      return {q: str};
    };

    $scope.countrySelected = function(selected) {
      window.alert('You have selected ' + selected.title);
    };

    $scope.countries = [
      {name: 'Afghanistan', code: 'AF'},
      {name: 'Aland Islands', code: 'AX'},
      {name: 'Albania', code: 'AL'},
      {name: 'Algeria', code: 'DZ'},
      {name: 'American Samoa', code: 'AS'},
      {name: 'AndorrA', code: 'AD'},
      {name: 'Angola', code: 'AO'},
      {name: 'Anguilla', code: 'AI'},
      {name: 'Antarctica', code: 'AQ'},
      {name: 'Antigua and Barbuda', code: 'AG'},
      {name: 'Argentina', code: 'AR'},
      {name: 'Armenia', code: 'AM'},
      {name: 'Aruba', code: 'AW'},
      {name: 'Australia', code: 'AU'},
      {name: 'Austria', code: 'AT'},
      {name: 'Azerbaijan', code: 'AZ'},
      {name: 'Bahamas', code: 'BS'},
      {name: 'Bahrain', code: 'BH'},
      {name: 'Bangladesh', code: 'BD'},
      {name: 'Barbados', code: 'BB'},
      {name: 'Belarus', code: 'BY'},
      {name: 'Belgium', code: 'BE'},
      {name: 'Belize', code: 'BZ'},
      {name: 'Benin', code: 'BJ'},
      {name: 'Bermuda', code: 'BM'},
      {name: 'Bhutan', code: 'BT'},
      {name: 'Bolivia', code: 'BO'},
      {name: 'Bosnia and Herzegovina', code: 'BA'},
      {name: 'Botswana', code: 'BW'},
      {name: 'Bouvet Island', code: 'BV'},
      {name: 'Brazil', code: 'BR'},
      {name: 'British Indian Ocean Territory', code: 'IO'},
      {name: 'Brunei Darussalam', code: 'BN'},
      {name: 'Bulgaria', code: 'BG'},
      {name: 'Burkina Faso', code: 'BF'},
      {name: 'Burundi', code: 'BI'},
      {name: 'Cambodia', code: 'KH'},
      {name: 'Cameroon', code: 'CM'},
      {name: 'Canada', code: 'CA'},
      {name: 'Cape Verde', code: 'CV'},
      {name: 'Cayman Islands', code: 'KY'},
      {name: 'Central African Republic', code: 'CF'},
      {name: 'Chad', code: 'TD'},
      {name: 'Chile', code: 'CL'},
      {name: 'China', code: 'CN'},
      {name: 'Christmas Island', code: 'CX'},
      {name: 'Cocos (Keeling) Islands', code: 'CC'},
      {name: 'Colombia', code: 'CO'},
      {name: 'Comoros', code: 'KM'},
      {name: 'Congo', code: 'CG'},
      {name: 'Congo, The Democratic Republic of the', code: 'CD'},
      {name: 'Cook Islands', code: 'CK'},
      {name: 'Costa Rica', code: 'CR'},
      {name: 'Cote D\'Ivoire', code: 'CI'},
      {name: 'Croatia', code: 'HR'},
      {name: 'Cuba', code: 'CU'},
      {name: 'Cyprus', code: 'CY'},
      {name: 'Czech Republic', code: 'CZ'},
      {name: 'Denmark', code: 'DK'},
      {name: 'Djibouti', code: 'DJ'},
      {name: 'Dominica', code: 'DM'},
      {name: 'Dominican Republic', code: 'DO'},
      {name: 'Ecuador', code: 'EC'},
      {name: 'Egypt', code: 'EG'},
      {name: 'El Salvador', code: 'SV'},
      {name: 'Equatorial Guinea', code: 'GQ'},
      {name: 'Eritrea', code: 'ER'},
      {name: 'Estonia', code: 'EE'},
      {name: 'Ethiopia', code: 'ET'},
      {name: 'Falkland Islands (Malvinas)', code: 'FK'},
      {name: 'Faroe Islands', code: 'FO'},
      {name: 'Fiji', code: 'FJ'},
      {name: 'Finland', code: 'FI'},
      {name: 'France', code: 'FR'},
      {name: 'French Guiana', code: 'GF'},
      {name: 'French Polynesia', code: 'PF'},
      {name: 'French Southern Territories', code: 'TF'},
      {name: 'Gabon', code: 'GA'},
      {name: 'Gambia', code: 'GM'},
      {name: 'Georgia', code: 'GE'},
      {name: 'Germany', code: 'DE'},
      {name: 'Ghana', code: 'GH'},
      {name: 'Gibraltar', code: 'GI'},
      {name: 'Greece', code: 'GR'},
      {name: 'Greenland', code: 'GL'},
      {name: 'Grenada', code: 'GD'},
      {name: 'Guadeloupe', code: 'GP'},
      {name: 'Guam', code: 'GU'},
      {name: 'Guatemala', code: 'GT'},
      {name: 'Guernsey', code: 'GG'},
      {name: 'Guinea', code: 'GN'},
      {name: 'Guinea-Bissau', code: 'GW'},
      {name: 'Guyana', code: 'GY'},
      {name: 'Haiti', code: 'HT'},
      {name: 'Heard Island and Mcdonald Islands', code: 'HM'},
      {name: 'Holy See (Vatican City State)', code: 'VA'},
      {name: 'Honduras', code: 'HN'},
      {name: 'Hong Kong', code: 'HK'},
      {name: 'Hungary', code: 'HU'},
      {name: 'Iceland', code: 'IS'},
      {name: 'India', code: 'IN'},
      {name: 'Indonesia', code: 'ID'},
      {name: 'Iran, Islamic Republic Of', code: 'IR'},
      {name: 'Iraq', code: 'IQ'},
      {name: 'Ireland', code: 'IE'},
      {name: 'Isle of Man', code: 'IM'},
      {name: 'Israel', code: 'IL'},
      {name: 'Italy', code: 'IT'},
      {name: 'Jamaica', code: 'JM'},
      {name: 'Japan', code: 'JP'},
      {name: 'Jersey', code: 'JE'},
      {name: 'Jordan', code: 'JO'},
      {name: 'Kazakhstan', code: 'KZ'},
      {name: 'Kenya', code: 'KE'},
      {name: 'Kiribati', code: 'KI'},
      {name: 'Korea, Democratic People\'S Republic of', code: 'KP'},
      {name: 'Korea, Republic of', code: 'KR'},
      {name: 'Kuwait', code: 'KW'},
      {name: 'Kyrgyzstan', code: 'KG'},
      {name: 'Lao People\'S Democratic Republic', code: 'LA'},
      {name: 'Latvia', code: 'LV'},
      {name: 'Lebanon', code: 'LB'},
      {name: 'Lesotho', code: 'LS'},
      {name: 'Liberia', code: 'LR'},
      {name: 'Libyan Arab Jamahiriya', code: 'LY'},
      {name: 'Liechtenstein', code: 'LI'},
      {name: 'Lithuania', code: 'LT'},
      {name: 'Luxembourg', code: 'LU'},
      {name: 'Macao', code: 'MO'},
      {name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK'},
      {name: 'Madagascar', code: 'MG'},
      {name: 'Malawi', code: 'MW'},
      {name: 'Malaysia', code: 'MY'},
      {name: 'Maldives', code: 'MV'},
      {name: 'Mali', code: 'ML'},
      {name: 'Malta', code: 'MT'},
      {name: 'Marshall Islands', code: 'MH'},
      {name: 'Martinique', code: 'MQ'},
      {name: 'Mauritania', code: 'MR'},
      {name: 'Mauritius', code: 'MU'},
      {name: 'Mayotte', code: 'YT'},
      {name: 'Mexico', code: 'MX'},
      {name: 'Micronesia, Federated States of', code: 'FM'},
      {name: 'Moldova, Republic of', code: 'MD'},
      {name: 'Monaco', code: 'MC'},
      {name: 'Mongolia', code: 'MN'},
      {name: 'Montserrat', code: 'MS'},
      {name: 'Morocco', code: 'MA'},
      {name: 'Mozambique', code: 'MZ'},
      {name: 'Myanmar', code: 'MM'},
      {name: 'Namibia', code: 'NA'},
      {name: 'Nauru', code: 'NR'},
      {name: 'Nepal', code: 'NP'},
      {name: 'Netherlands', code: 'NL'},
      {name: 'Netherlands Antilles', code: 'AN'},
      {name: 'New Caledonia', code: 'NC'},
      {name: 'New Zealand', code: 'NZ'},
      {name: 'Nicaragua', code: 'NI'},
      {name: 'Niger', code: 'NE'},
      {name: 'Nigeria', code: 'NG'},
      {name: 'Niue', code: 'NU'},
      {name: 'Norfolk Island', code: 'NF'},
      {name: 'Northern Mariana Islands', code: 'MP'},
      {name: 'Norway', code: 'NO'},
      {name: 'Oman', code: 'OM'},
      {name: 'Pakistan', code: 'PK'},
      {name: 'Palau', code: 'PW'},
      {name: 'Palestinian Territory, Occupied', code: 'PS'},
      {name: 'Panama', code: 'PA'},
      {name: 'Papua New Guinea', code: 'PG'},
      {name: 'Paraguay', code: 'PY'},
      {name: 'Peru', code: 'PE'},
      {name: 'Philippines', code: 'PH'},
      {name: 'Pitcairn', code: 'PN'},
      {name: 'Poland', code: 'PL'},
      {name: 'Portugal', code: 'PT'},
      {name: 'Puerto Rico', code: 'PR'},
      {name: 'Qatar', code: 'QA'},
      {name: 'Reunion', code: 'RE'},
      {name: 'Romania', code: 'RO'},
      {name: 'Russian Federation', code: 'RU'},
      {name: 'RWANDA', code: 'RW'},
      {name: 'Saint Helena', code: 'SH'},
      {name: 'Saint Kitts and Nevis', code: 'KN'},
      {name: 'Saint Lucia', code: 'LC'},
      {name: 'Saint Pierre and Miquelon', code: 'PM'},
      {name: 'Saint Vincent and the Grenadines', code: 'VC'},
      {name: 'Samoa', code: 'WS'},
      {name: 'San Marino', code: 'SM'},
      {name: 'Sao Tome and Principe', code: 'ST'},
      {name: 'Saudi Arabia', code: 'SA'},
      {name: 'Senegal', code: 'SN'},
      {name: 'Serbia and Montenegro', code: 'CS'},
      {name: 'Seychelles', code: 'SC'},
      {name: 'Sierra Leone', code: 'SL'},
      {name: 'Singapore', code: 'SG'},
      {name: 'Slovakia', code: 'SK'},
      {name: 'Slovenia', code: 'SI'},
      {name: 'Solomon Islands', code: 'SB'},
      {name: 'Somalia', code: 'SO'},
      {name: 'South Africa', code: 'ZA'},
      {name: 'South Georgia and the South Sandwich Islands', code: 'GS'},
      {name: 'Spain', code: 'ES'},
      {name: 'Sri Lanka', code: 'LK'},
      {name: 'Sudan', code: 'SD'},
      {name: 'Suriname', code: 'SR'},
      {name: 'Svalbard and Jan Mayen', code: 'SJ'},
      {name: 'Swaziland', code: 'SZ'},
      {name: 'Sweden', code: 'SE'},
      {name: 'Switzerland', code: 'CH'},
      {name: 'Syrian Arab Republic', code: 'SY'},
      {name: 'Taiwan, Province of China', code: 'TW'},
      {name: 'Tajikistan', code: 'TJ'},
      {name: 'Tanzania, United Republic of', code: 'TZ'},
      {name: 'Thailand', code: 'TH'},
      {name: 'Timor-Leste', code: 'TL'},
      {name: 'Togo', code: 'TG'},
      {name: 'Tokelau', code: 'TK'},
      {name: 'Tonga', code: 'TO'},
      {name: 'Trinidad and Tobago', code: 'TT'},
      {name: 'Tunisia', code: 'TN'},
      {name: 'Turkey', code: 'TR'},
      {name: 'Turkmenistan', code: 'TM'},
      {name: 'Turks and Caicos Islands', code: 'TC'},
      {name: 'Tuvalu', code: 'TV'},
      {name: 'Uganda', code: 'UG'},
      {name: 'Ukraine', code: 'UA'},
      {name: 'United Arab Emirates', code: 'AE'},
      {name: 'United Kingdom', code: 'GB'},
      {name: 'United States', code: 'US'},
      {name: 'United States Minor Outlying Islands', code: 'UM'},
      {name: 'Uruguay', code: 'UY'},
      {name: 'Uzbekistan', code: 'UZ'},
      {name: 'Vanuatu', code: 'VU'},
      {name: 'Venezuela', code: 'VE'},
      {name: 'Vietnam', code: 'VN'},
      {name: 'Virgin Islands, British', code: 'VG'},
      {name: 'Virgin Islands, U.S.', code: 'VI'},
      {name: 'Wallis and Futuna', code: 'WF'},
      {name: 'Western Sahara', code: 'EH'},
      {name: 'Yemen', code: 'YE'},
      {name: 'Zambia', code: 'ZM'},
      {name: 'Zimbabwe', code: 'ZW'}
    ];

  }
]);
/* Styles go here */

/*
 * angucomplete-alt
 * Autocomplete directive for AngularJS
 * This is a fork of Daryl Rowland's angucomplete with some extra features.
 * By Hidenari Nozaki
 */

/*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */

'use strict';

(function (root, factory) {
  if (typeof module !== 'undefined' && module.exports) {
    // CommonJS
    module.exports = factory(require('angular'));
  } else if (typeof define === 'function' && define.amd) {
    // AMD
    define(['angular'], factory);
  } else {
    // Global Variables
    factory(root.angular);
  }
}(window, function (angular) {

  angular.module('angucomplete-alt', [] )
    .directive('angucompleteAlt', ['$q', '$parse', '$http', '$sce', '$timeout', '$templateCache', function ($q, $parse, $http, $sce, $timeout, $templateCache) {
    // keyboard events
    var KEY_DW  = 40;
    var KEY_RT  = 39;
    var KEY_UP  = 38;
    var KEY_LF  = 37;
    var KEY_ES  = 27;
    var KEY_EN  = 13;
    var KEY_BS  =  8;
    var KEY_DEL = 46;
    var KEY_TAB =  9;

    var MIN_LENGTH = 3;
    var MAX_LENGTH = 524288;  // the default max length per the html maxlength attribute
    var PAUSE = 500;
    var BLUR_TIMEOUT = 200;

    // string constants
    var REQUIRED_CLASS = 'autocomplete-required';
    var TEXT_SEARCHING = 'Searching...';
    var TEXT_NORESULTS = 'No results found';
    var TEMPLATE_URL = '/angucomplete-alt/index.html';

    // Set the default template for this directive
    $templateCache.put(TEMPLATE_URL,
        '<div class="angucomplete-holder" ng-class="{\'angucomplete-dropdown-visible\': showDropdown}">' +
        '  <input id="{{id}}_value" name={{inputName}} ng-class="{\'angucomplete-input-not-empty\': notEmpty}" ng-model="searchStr" ng-disabled="disableInput" type="{{type}}" placeholder="{{placeholder}}" maxlength="{{maxlength}}" ng-focus="onFocusHandler()" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults($event)" autocapitalize="off" autocorrect="off" autocomplete="off" ng-change="inputChangeHandler(searchStr)"/>' +
        '  <div id="{{id}}_dropdown" class="angucomplete-dropdown" ng-show="showDropdown">' +
        '    <div class="angucomplete-searching" ng-show="searching" ng-bind="textSearching"></div>' +
        '    <div class="angucomplete-searching" ng-show="!searching && (!results || results.length == 0)" ng-bind="textNoResults"></div>' +
        '    <div class="angucomplete-row" ng-repeat="result in results" ng-click="selectResult(result)" ng-mouseenter="hoverRow($index)" ng-class="{\'angucomplete-selected-row\': $index == currentIndex}">' +
        '      <div ng-if="imageField" class="angucomplete-image-holder">' +
        '        <img ng-if="result.image && result.image != \'\'" ng-src="{{result.image}}" class="angucomplete-image"/>' +
        '        <div ng-if="!result.image && result.image != \'\'" class="angucomplete-image-default"></div>' +
        '      </div>' +
        '      <div class="angucomplete-title" ng-if="matchClass" ng-bind-html="result.title"></div>' +
        '      <div class="angucomplete-title" ng-if="!matchClass">{{ result.title }}</div>' +
        '      <div ng-if="matchClass && result.description && result.description != \'\'" class="angucomplete-description" ng-bind-html="result.description"></div>' +
        '      <div ng-if="!matchClass && result.description && result.description != \'\'" class="angucomplete-description">{{result.description}}</div>' +
        '    </div>' +
        '  </div>' +
        '</div>'
    );

    return {
      restrict: 'EA',
      require: '^?form',
      scope: {
        selectedObject: '=',
        disableInput: '=',
        initialValue: '=',
        localData: '=',
        remoteUrlRequestFormatter: '=',
        remoteUrlRequestWithCredentials: '@',
        remoteUrlResponseFormatter: '=',
        remoteUrlErrorCallback: '=',
        remoteApiHandler: '=',
        id: '@',
        type: '@',
        placeholder: '@',
        remoteUrl: '@',
        remoteUrlDataField: '@',
        titleField: '@',
        descriptionField: '@',
        imageField: '@',
        inputClass: '@',
        pause: '@',
        searchFields: '@',
        minlength: '@',
        matchClass: '@',
        clearSelected: '@',
        overrideSuggestions: '@',
        fieldRequired: '@',
        fieldRequiredClass: '@',
        inputChanged: '=',
        autoMatch: '@',
        focusOut: '&',
        focusIn: '&',
        inputName: '@'
      },
      templateUrl: function(element, attrs) {
        return attrs.templateUrl || TEMPLATE_URL;
      },
      link: function(scope, elem, attrs, ctrl) {
        var inputField = elem.find('input');
        var minlength = MIN_LENGTH;
        var searchTimer = null;
        var hideTimer;
        var requiredClassName = REQUIRED_CLASS;
        var responseFormatter;
        var validState = null;
        var httpCanceller = null;
        var dd = elem[0].querySelector('.angucomplete-dropdown');
        var isScrollOn = false;
        var mousedownOn = null;
        var unbindInitialValue;

        elem.on('mousedown', function(event) {
          if (event.target.id) {
            mousedownOn = event.target.id;
          }
          else {
            mousedownOn = event.target.className;
          }
        });

        scope.currentIndex = null;
        scope.searching = false;
        unbindInitialValue = scope.$watch('initialValue', function(newval, oldval) {

          if (newval) {
            unbindInitialValue();

            if (typeof newval === 'object') {
              scope.searchStr = extractTitle(newval);
              callOrAssign({originalObject: newval});
            } else if (typeof newval === 'string' && newval.length > 0) {
              scope.searchStr = newval;
            } else {
              if (console && console.error) {
                console.error('Tried to set initial value of angucomplete to', newval, 'which is an invalid value');
              }
            }

            handleRequired(true);
          }
        });

        scope.$on('angucomplete-alt:clearInput', function (event, elementId) {
          if (!elementId || elementId === scope.id) {
            scope.searchStr = null;
            handleRequired(false);
            clearResults();
          }
        });

        // for IE8 quirkiness about event.which
        function ie8EventNormalizer(event) {
          return event.which ? event.which : event.keyCode;
        }

        function callOrAssign(value) {
          if (typeof scope.selectedObject === 'function') {
            scope.selectedObject(value);
          }
          else {
            scope.selectedObject = value;
          }

          if (value) {
            handleRequired(true);
          }
          else {
            handleRequired(false);
          }
        }

        function callFunctionOrIdentity(fn) {
          return function(data) {
            return scope[fn] ? scope[fn](data) : data;
          };
        }

        function setInputString(str) {
          callOrAssign({originalObject: str});

          if (scope.clearSelected) {
            scope.searchStr = null;
          }
          clearResults();
        }

        function extractTitle(data) {
          // split title fields and run extractValue for each and join with ' '
          return scope.titleField.split(',')
            .map(function(field) {
              return extractValue(data, field);
            })
            .join(' ');
        }

        function extractValue(obj, key) {
          var keys, result;
          if (key) {
            keys= key.split('.');
            result = obj;
            keys.forEach(function(k) { result = result[k]; });
          }
          else {
            result = obj;
          }
          return result;
        }

        function findMatchString(target, str) {
          var result, matches, re;
          // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
          // Escape user input to be treated as a literal string within a regular expression
          re = new RegExp(str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
          if (!target) { return; }
          matches = target.match(re);
          if (matches) {
            result = target.replace(re,
                '<span class="'+ scope.matchClass +'">'+ matches[0] +'</span>');
          }
          else {
            result = target;
          }
          return $sce.trustAsHtml(result);
        }

        function handleRequired(valid) {
          scope.notEmpty = valid;
          validState = scope.searchStr;
          if (scope.fieldRequired && ctrl) {
            ctrl.$setValidity(requiredClassName, valid);
          }
        }

        function keyupHandler(event) {
          var which = ie8EventNormalizer(event);
          if (which === KEY_LF || which === KEY_RT) {
            // do nothing
            return;
          }

          if (which === KEY_UP || which === KEY_EN) {
            event.preventDefault();
          }
          else if (which === KEY_DW) {
            event.preventDefault();
            if (!scope.showDropdown && scope.searchStr && scope.searchStr.length >= minlength) {
              initResults();
              scope.searching = true;
              searchTimerComplete(scope.searchStr);
            }
          }
          else if (which === KEY_ES) {
            clearResults();
            scope.$apply(function() {
              inputField.val(scope.searchStr);
            });
          }
          else {
            if (minlength === 0 && !scope.searchStr) {
              return;
            }

            if (!scope.searchStr || scope.searchStr === '') {
              scope.showDropdown = false;
            } else if (scope.searchStr.length >= minlength) {
              initResults();

              if (searchTimer) {
                $timeout.cancel(searchTimer);
              }

              scope.searching = true;

              searchTimer = $timeout(function() {
                searchTimerComplete(scope.searchStr);
              }, scope.pause);
            }

            if (validState && validState !== scope.searchStr && !scope.clearSelected) {
              callOrAssign(undefined);
            }
          }
        }

        function handleOverrideSuggestions(event) {
          if (scope.overrideSuggestions &&
              !(scope.selectedObject && scope.selectedObject.originalObject === scope.searchStr)) {
            if (event) {
              event.preventDefault();
            }
            setInputString(scope.searchStr);
          }
        }

        function dropdownRowOffsetHeight(row) {
          var css = getComputedStyle(row);
          return row.offsetHeight +
            parseInt(css.marginTop, 10) + parseInt(css.marginBottom, 10);
        }

        function dropdownHeight() {
          return dd.getBoundingClientRect().top +
            parseInt(getComputedStyle(dd).maxHeight, 10);
        }

        function dropdownRow() {
          return elem[0].querySelectorAll('.angucomplete-row')[scope.currentIndex];
        }

        function dropdownRowTop() {
          return dropdownRow().getBoundingClientRect().top -
            (dd.getBoundingClientRect().top +
             parseInt(getComputedStyle(dd).paddingTop, 10));
        }

        function dropdownScrollTopTo(offset) {
          dd.scrollTop = dd.scrollTop + offset;
        }

        function updateInputField(){
          var current = scope.results[scope.currentIndex];
          if (scope.matchClass) {
            inputField.val(extractTitle(current.originalObject));
          }
          else {
            inputField.val(current.title);
          }
        }

        function keydownHandler(event) {
          var which = ie8EventNormalizer(event);
          var row = null;
          var rowTop = null;

          if (which === KEY_EN && scope.results) {
            if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) {
              event.preventDefault();
              scope.selectResult(scope.results[scope.currentIndex]);
            } else {
              handleOverrideSuggestions(event);
              clearResults();
            }
            scope.$apply();
          } else if (which === KEY_DW && scope.results) {
            event.preventDefault();
            if ((scope.currentIndex + 1) < scope.results.length && scope.showDropdown) {
              scope.$apply(function() {
                scope.currentIndex ++;
                updateInputField();
              });

              if (isScrollOn) {
                row = dropdownRow();
                if (dropdownHeight() < row.getBoundingClientRect().bottom) {
                  dropdownScrollTopTo(dropdownRowOffsetHeight(row));
                }
              }
            }
          } else if (which === KEY_UP && scope.results) {
            event.preventDefault();
            if (scope.currentIndex >= 1) {
              scope.$apply(function() {
                scope.currentIndex --;
                updateInputField();
              });

              if (isScrollOn) {
                rowTop = dropdownRowTop();
                if (rowTop < 0) {
                  dropdownScrollTopTo(rowTop - 1);
                }
              }
            }
            else if (scope.currentIndex === 0) {
              scope.$apply(function() {
                scope.currentIndex = -1;
                inputField.val(scope.searchStr);
              });
            }
          } else if (which === KEY_TAB) {
            if (scope.results && scope.results.length > 0 && scope.showDropdown) {
              if (scope.currentIndex === -1 && scope.overrideSuggestions) {
                // intentionally not sending event so that it does not
                // prevent default tab behavior
                handleOverrideSuggestions();
              }
              else {
                if (scope.currentIndex === -1) {
                  scope.currentIndex = 0;
                }
                scope.selectResult(scope.results[scope.currentIndex]);
                scope.$digest();
              }
            }
            else {
              // no results
              // intentionally not sending event so that it does not
              // prevent default tab behavior
              if (scope.searchStr && scope.searchStr.length > 0) {
                handleOverrideSuggestions();
              }
            }
          }
        }

        function httpSuccessCallbackGen(str) {
          return function(responseData, status, headers, config) {
            // normalize return obejct from promise
            if (!status && !headers && !config) {
              responseData = responseData.data;
            }
            scope.searching = false;
            processResults(
              extractValue(responseFormatter(responseData), scope.remoteUrlDataField),
              str);
          };
        }

        function httpErrorCallback(errorRes, status, headers, config) {
          // normalize return obejct from promise
          if (!status && !headers && !config) {
            status = errorRes.status;
          }
          if (status !== 0) {
            if (scope.remoteUrlErrorCallback) {
              scope.remoteUrlErrorCallback(errorRes, status, headers, config);
            }
            else {
              if (console && console.error) {
                console.error('http error');
              }
            }
          }
        }

        function cancelHttpRequest() {
          if (httpCanceller) {
            httpCanceller.resolve();
          }
        }

        function getRemoteResults(str) {
          var params = {},
              url = scope.remoteUrl + encodeURIComponent(str);
          if (scope.remoteUrlRequestFormatter) {
            params = {params: scope.remoteUrlRequestFormatter(str)};
            url = scope.remoteUrl;
          }
          if (!!scope.remoteUrlRequestWithCredentials) {
            params.withCredentials = true;
          }
          cancelHttpRequest();
          httpCanceller = $q.defer();
          params.timeout = httpCanceller.promise;
          $http.get(url, params)
            .success(httpSuccessCallbackGen(str))
            .error(httpErrorCallback);
        }

        function getRemoteResultsWithCustomHandler(str) {
          cancelHttpRequest();

          httpCanceller = $q.defer();

          scope.remoteApiHandler(str, httpCanceller.promise)
            .then(httpSuccessCallbackGen(str))
            .catch(httpErrorCallback);
        }

        function clearResults() {
          scope.showDropdown = false;
          scope.results = [];
          if (dd) {
            dd.scrollTop = 0;
          }
        }

        function initResults() {
          scope.showDropdown = true;
          scope.currentIndex = -1;
          scope.results = [];
        }

        function getLocalResults(str) {
          var i, match, s, value,
              searchFields = scope.searchFields.split(','),
              matches = [];

          for (i = 0; i < scope.localData.length; i++) {
            match = false;

            for (s = 0; s < searchFields.length; s++) {
              value = extractValue(scope.localData[i], searchFields[s]) || '';
              match = match || (value.toLowerCase().indexOf(str.toLowerCase()) >= 0);
            }

            if (match) {
              matches[matches.length] = scope.localData[i];
            }
          }

          scope.searching = false;
          processResults(matches, str);
        }

        function checkExactMatch(result, obj, str){
          if (!str) { return; }
          for(var key in obj){
            if(obj[key].toLowerCase() === str.toLowerCase()){
              scope.selectResult(result);
              return;
            }
          }
        }

        function searchTimerComplete(str) {
          // Begin the search
          if (!str || str.length < minlength) {
            return;
          }
          if (scope.localData) {
            scope.$apply(function() {
              getLocalResults(str);
            });
          }
          else if (scope.remoteApiHandler) {
            getRemoteResultsWithCustomHandler(str);
          } else {
            getRemoteResults(str);
          }
        }

        function processResults(responseData, str) {
          var i, description, image, text, formattedText, formattedDesc;

          if (responseData && responseData.length > 0) {
            scope.results = [];

            for (i = 0; i < responseData.length; i++) {
              if (scope.titleField && scope.titleField !== '') {
                text = formattedText = extractTitle(responseData[i]);
              }

              description = '';
              if (scope.descriptionField) {
                description = formattedDesc = extractValue(responseData[i], scope.descriptionField);
              }

              image = '';
              if (scope.imageField) {
                image = extractValue(responseData[i], scope.imageField);
              }

              if (scope.matchClass) {
                formattedText = findMatchString(text, str);
                formattedDesc = findMatchString(description, str);
              }

              scope.results[scope.results.length] = {
                title: formattedText,
                description: formattedDesc,
                image: image,
                originalObject: responseData[i]
              };

              if (scope.autoMatch) {
                checkExactMatch(scope.results[scope.results.length-1],
                    {title: text, desc: description || ''}, scope.searchStr);
              }
            }

          } else {
            scope.results = [];
          }
        }

        function showAll() {
          if (scope.localData) {
            processResults(scope.localData, '');
          }
          else if (scope.remoteApiHandler) {
            getRemoteResultsWithCustomHandler('');
          }
          else {
            getRemoteResults('');
          }
        }

        scope.onFocusHandler = function() {
          if (scope.focusIn) {
            scope.focusIn();
          }
          if (minlength === 0 && (!scope.searchStr || scope.searchStr.length === 0)) {
            scope.showDropdown = true;
            showAll();
          }
        };

        scope.hideResults = function(event) {
          if (mousedownOn && mousedownOn.indexOf('angucomplete') >= 0) {
            mousedownOn = null;
          }
          else {
            hideTimer = $timeout(function() {
              clearResults();
              scope.$apply(function() {
                if (scope.searchStr && scope.searchStr.length > 0) {
                  inputField.val(scope.searchStr);
                }
              });
            }, BLUR_TIMEOUT);
            cancelHttpRequest();

            if (scope.focusOut) {
              scope.focusOut();
            }

            if (scope.overrideSuggestions) {
              if (scope.searchStr && scope.searchStr.length > 0 && scope.currentIndex === -1) {
                handleOverrideSuggestions();
              }
            }
          }
        };

        scope.resetHideResults = function() {
          if (hideTimer) {
            $timeout.cancel(hideTimer);
          }
        };

        scope.hoverRow = function(index) {
          scope.currentIndex = index;
        };

        scope.selectResult = function(result) {
          // Restore original values
          if (scope.matchClass) {
            result.title = extractTitle(result.originalObject);
            result.description = extractValue(result.originalObject, scope.descriptionField);
          }

          if (scope.clearSelected) {
            scope.searchStr = null;
          }
          else {
            scope.searchStr = result.title;
          }
          callOrAssign(result);
          clearResults();
        };

        scope.inputChangeHandler = function(str) {
          if (str.length < minlength) {
            clearResults();
          }
          else if (str.length === 0 && minlength === 0) {
            scope.searching = false;
            showAll();
          }

          if (scope.inputChanged) {
            str = scope.inputChanged(str);
          }
          return str;
        };

        // check required
        if (scope.fieldRequiredClass && scope.fieldRequiredClass !== '') {
          requiredClassName = scope.fieldRequiredClass;
        }

        // check min length
        if (scope.minlength && scope.minlength !== '') {
          minlength = parseInt(scope.minlength, 10);
        }

        // check pause time
        if (!scope.pause) {
          scope.pause = PAUSE;
        }

        // check clearSelected
        if (!scope.clearSelected) {
          scope.clearSelected = false;
        }

        // check override suggestions
        if (!scope.overrideSuggestions) {
          scope.overrideSuggestions = false;
        }

        // check required field
        if (scope.fieldRequired && ctrl) {
          // check initial value, if given, set validitity to true
          if (scope.initialValue) {
            handleRequired(true);
          }
          else {
            handleRequired(false);
          }
        }

        scope.type = attrs.type ? attrs.type : 'text';

        // set strings for "Searching..." and "No results"
        scope.textSearching = attrs.textSearching ? attrs.textSearching : TEXT_SEARCHING;
        scope.textNoResults = attrs.textNoResults ? attrs.textNoResults : TEXT_NORESULTS;

        // set max length (default to maxlength deault from html
        scope.maxlength = attrs.maxlength ? attrs.maxlength : MAX_LENGTH;

        // register events
        inputField.on('keydown', keydownHandler);
        inputField.on('keyup', keyupHandler);

        // set response formatter
        responseFormatter = callFunctionOrIdentity('remoteUrlResponseFormatter');

        scope.$on('$destroy', function() {
          // take care of required validity when it gets destroyed
          handleRequired(true);
        });

        // set isScrollOn
        $timeout(function() {
          var css = getComputedStyle(dd);
          isScrollOn = css.maxHeight && css.overflowY === 'auto';
        });
      }
    };
  }]);

}));
.angucomplete-holder {
    position: relative;
}

.angucomplete-dropdown {
    border-color: #ececec;
    border-width: 1px;
    border-style: solid;
    border-radius: 2px;
    width: 250px;
    padding: 6px;
    cursor: pointer;
    z-index: 9999;
    position: absolute;
    /*top: 32px;
    left: 0px;
    */
    margin-top: -6px;
    background-color: #ffffff;
}

.angucomplete-searching {
    color: #acacac;
    font-size: 14px;
}

.angucomplete-description {
    font-size: 14px;
}

.angucomplete-row {
    padding: 5px;
    color: #000000;
    margin-bottom: 4px;
    clear: both;
}

.angucomplete-selected-row {
    background-color: lightblue;
    color: #ffffff;
}

.angucomplete-image-holder {
    padding-top: 2px;
    float: left;
    margin-right: 10px;
    margin-left: 5px;
}

.angucomplete-image {
    height: 34px;
    width: 34px;
    border-radius: 50%;
    border-color: #ececec;
    border-style: solid;
    border-width: 1px;
}

.angucomplete-image-default {
    /* Add your own default image here
     background-image: url('/assets/default.png');
    */
    background-position: center;
    background-size: contain;
    height: 34px;
    width: 34px;
}