3 * Autocomplete directive for AngularJS
7 angular.module('angucomplete', [] )
8 .directive('angucomplete', function ($parse, $http, $sce, $timeout) {
13 "placeholder": "@placeholder",
14 "selectedObject": "=selectedobject",
16 "dataField": "@datafield",
17 "titleField": "@titlefield",
18 "descriptionField": "@descriptionfield",
19 "imageField": "@imagefield",
20 "imageUri": "@imageuri",
21 "inputClass": "@inputclass",
22 "userPause": "@pause",
23 "localData": "=localdata",
24 "searchFields": "@searchfields",
25 "minLengthUser": "@minlength",
26 "matchClass": "@matchclass"
28 template: '<div class="angucomplete-holder"><input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" onmouseup="this.select();" ng-focus="resetHideResults()" ng-blur="hideResults()" /><div id="{{id}}_dropdown" class="angucomplete-dropdown" style="height:300px;overflow:auto;" ng-if="showDropdown"><div class="angucomplete-searching" ng-show="searching">Searching...</div><div class="angucomplete-searching" ng-show="!searching && (!results || results.length == 0)">No results found</div><div class="angucomplete-row" ng-repeat="result in results" ng-click="selectResult(result)" ng-mouseover="hoverRow()" 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="result.description && result.description != \'\'" class="angucomplete-description">{{result.description}}</div></div></div></div>',
30 link: function($scope, elem, attrs) {
31 $scope.lastSearchTerm = null;
32 $scope.currentIndex = null;
33 $scope.justChanged = false;
34 $scope.searchTimer = null;
35 $scope.hideTimer = null;
36 $scope.searching = false;
39 $scope.searchStr = null;
41 if ($scope.minLengthUser && $scope.minLengthUser != "") {
42 $scope.minLength = $scope.minLengthUser;
45 if ($scope.userPause) {
46 $scope.pause = $scope.userPause;
49 isNewSearchNeeded = function(newTerm, oldTerm) {
50 return newTerm.length >= $scope.minLength && newTerm != oldTerm
53 $scope.processResults = function(responseData, str) {
54 if (responseData && responseData.length > 0) {
58 if ($scope.titleField && $scope.titleField != "") {
59 titleFields = $scope.titleField.split(",");
62 for (var i = 0; i < responseData.length; i++) {
63 // Get title variables
66 for (var t = 0; t < titleFields.length; t++) {
67 titleCode.push(responseData[i][titleFields[t]]);
71 if ($scope.descriptionField) {
72 description = responseData[i][$scope.descriptionField];
76 if ($scope.imageUri) {
77 imageUri = $scope.imageUri;
81 if ($scope.imageField) {
82 image = imageUri + responseData[i][$scope.imageField];
85 var text = titleCode.join(' ');
86 if ($scope.matchClass) {
87 var re = new RegExp(str, 'i');
88 var strPart = text.match(re)[0];
89 text = $sce.trustAsHtml(text.replace(re, '<span class="'+ $scope.matchClass +'">'+ strPart +'</span>'));
94 description: description,
96 originalObject: responseData[i]
99 $scope.results[$scope.results.length] = resultRow;
108 $scope.searchTimerComplete = function(str) {
111 if (str.length >= $scope.minLength) {
112 if ($scope.localData) {
113 var searchFields = $scope.searchFields.split(",");
117 for (var i = 0; i < $scope.localData.length; i++) {
120 for (var s = 0; s < searchFields.length; s++) {
121 match = match || (typeof $scope.localData[i][searchFields[s]] === 'string' && typeof str === 'string' && $scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase()) >= 0);
125 matches[matches.length] = $scope.localData[i];
129 $scope.searching = false;
130 $scope.processResults(matches, str);
133 $http.get($scope.url + str, {}).
134 success(function(responseData, status, headers, config) {
135 $scope.searching = false;
136 $scope.processResults((($scope.dataField) ? responseData[$scope.dataField] : responseData ), str);
138 error(function(data, status, headers, config) {
139 console.log("error");
145 $scope.hideResults = function() {
146 $scope.hideTimer = $timeout(function() {
147 $scope.showDropdown = false;
151 $scope.resetHideResults = function() {
152 if($scope.hideTimer) {
153 $timeout.cancel($scope.hideTimer);
157 $scope.hoverRow = function(index) {
158 $scope.currentIndex = index;
161 $scope.keyPressed = function(event) {
162 if (!(event.which == 38 || event.which == 40 || event.which == 13)) {
163 if (!$scope.searchStr || $scope.searchStr == "") {
164 $scope.showDropdown = false;
165 $scope.lastSearchTerm = null
166 } else if (isNewSearchNeeded($scope.searchStr, $scope.lastSearchTerm)) {
167 $scope.lastSearchTerm = $scope.searchStr
168 $scope.showDropdown = true;
169 $scope.currentIndex = -1;
172 if ($scope.searchTimer) {
173 $timeout.cancel($scope.searchTimer);
176 $scope.searching = true;
178 $scope.searchTimer = $timeout(function() {
179 $scope.searchTimerComplete($scope.searchStr);
183 event.preventDefault();
187 $scope.selectResult = function(result) {
188 if ($scope.matchClass) {
189 result.title = result.title.toString().replace(/(<([^>]+)>)/ig, '');
191 $scope.searchStr = $scope.lastSearchTerm = result.title;
192 $scope.selectedObject = result;
193 $scope.showDropdown = false;
198 var inputField = elem.find('input');
200 inputField.on('keyup', $scope.keyPressed);
202 elem.on("keyup", function (event) {
203 if(event.which === 40) {
204 if ($scope.results && ($scope.currentIndex + 1) < $scope.results.length) {
205 $scope.currentIndex ++;
207 event.preventDefault;
208 event.stopPropagation();
212 } else if(event.which == 38) {
213 if ($scope.currentIndex >= 1) {
214 $scope.currentIndex --;
216 event.preventDefault;
217 event.stopPropagation();
220 } else if (event.which == 13) {
221 if ($scope.results && $scope.currentIndex >= 0 && $scope.currentIndex < $scope.results.length) {
222 $scope.selectResult($scope.results[$scope.currentIndex]);
224 event.preventDefault;
225 event.stopPropagation();
229 event.preventDefault;
230 event.stopPropagation();
233 } else if (event.which == 27) {
235 $scope.showDropdown = false;
237 } else if (event.which == 8) {
238 $scope.selectedObject = null;