Project

General

Profile

1
/**
2
 * Angucomplete
3
 * Autocomplete directive for AngularJS
4
 * By Daryl Rowland
5
 */
6

    
7
angular.module('angucomplete', [] )
8
    .directive('angucomplete', function ($parse, $http, $sce, $timeout) {
9
    return {
10
        restrict: 'EA',
11
        scope: {
12
            "id": "@id",
13
            "placeholder": "@placeholder",
14
            "selectedObject": "=selectedobject",
15
            "url": "@url",
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"
27
        },
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" 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-mousedown="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>',
29

    
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;
37
            $scope.pause = 500;
38
            $scope.minLength = 3;
39
            $scope.searchStr = null;
40

    
41
            if ($scope.minLengthUser && $scope.minLengthUser != "") {
42
                $scope.minLength = $scope.minLengthUser;
43
            }
44

    
45
            if ($scope.userPause) {
46
                $scope.pause = $scope.userPause;
47
            }
48

    
49
            isNewSearchNeeded = function(newTerm, oldTerm) {
50
                return newTerm.length >= $scope.minLength && newTerm != oldTerm
51
            }
52

    
53
            $scope.processResults = function(responseData, str) {
54
                if (responseData && responseData.length > 0) {
55
                    $scope.results = [];
56

    
57
                    var titleFields = [];
58
                    if ($scope.titleField && $scope.titleField != "") {
59
                        titleFields = $scope.titleField.split(",");
60
                    }
61

    
62
                    for (var i = 0; i < responseData.length; i++) {
63
                        // Get title variables
64
                        var titleCode = [];
65

    
66
                        for (var t = 0; t < titleFields.length; t++) {
67
                            titleCode.push(responseData[i][titleFields[t]]);
68
                        }
69

    
70
                        var description = "";
71
                        if ($scope.descriptionField) {
72
                            description = responseData[i][$scope.descriptionField];
73
                        }
74

    
75
                        var imageUri = "";
76
                        if ($scope.imageUri) {
77
                            imageUri = $scope.imageUri;
78
                        }
79

    
80
                        var image = "";
81
                        if ($scope.imageField) {
82
                            image = imageUri + responseData[i][$scope.imageField];
83
                        }
84

    
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>'));
90
                        }
91

    
92
                        var resultRow = {
93
                            title: text,
94
                            description: description,
95
                            image: image,
96
                            originalObject: responseData[i]
97
                        }
98

    
99
                        $scope.results[$scope.results.length] = resultRow;
100
                    }
101

    
102

    
103
                } else {
104
                    $scope.results = [];
105
                }
106
            }
107

    
108
            $scope.searchTimerComplete = function(str) {
109
                // Begin the search
110

    
111
                if (str.length >= $scope.minLength) {
112
                    if ($scope.localData) {
113
                        var searchFields = $scope.searchFields.split(",");
114

    
115
                        var matches = [];
116

    
117
                        for (var i = 0; i < $scope.localData.length; i++) {
118
                            var match = false;
119

    
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);
122
                            }
123

    
124
                            if (match) {
125
                                matches[matches.length] = $scope.localData[i];
126
                            }
127
                        }
128

    
129
                        $scope.searching = false;
130
                        $scope.processResults(matches, str);
131

    
132
                    } else {
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);
137
                            }).
138
                            error(function(data, status, headers, config) {
139
                                console.log("error");
140
                            });
141
                    }
142
                }
143
            }
144

    
145
            $scope.hideResults = function() {
146
                $scope.hideTimer = $timeout(function() {
147
                    $scope.showDropdown = false;
148
                }, $scope.pause);
149
            };
150

    
151
            $scope.resetHideResults = function() {
152
                if($scope.hideTimer) {
153
                    $timeout.cancel($scope.hideTimer);
154
                };
155
            };
156

    
157
            $scope.hoverRow = function(index) {
158
                $scope.currentIndex = index;
159
            }
160

    
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;
170
                        $scope.results = [];
171

    
172
                        if ($scope.searchTimer) {
173
                            $timeout.cancel($scope.searchTimer);
174
                        }
175

    
176
                        $scope.searching = true;
177

    
178
                        $scope.searchTimer = $timeout(function() {
179
                            $scope.searchTimerComplete($scope.searchStr);
180
                        }, $scope.pause);
181
                    }
182
                } else {
183
                    event.preventDefault();
184
                }
185
            }
186

    
187
            $scope.selectResult = function(result) {
188
                if ($scope.matchClass) {
189
                    result.title = result.title.toString().replace(/(<([^>]+)>)/ig, '');
190
                }
191
                $scope.searchStr = $scope.lastSearchTerm = result.title;
192
                $scope.selectedObject = result;
193
                $scope.showDropdown = false;
194
                $scope.results = [];
195
                //$scope.$apply();
196
            }
197

    
198
            var inputField = elem.find('input');
199

    
200
            inputField.on('keyup', $scope.keyPressed);
201

    
202
            elem.on("keyup", function (event) {
203
                if(event.which === 40) {
204
                    if ($scope.results && ($scope.currentIndex + 1) < $scope.results.length) {
205
                        $scope.currentIndex ++;
206
                        $scope.$apply();
207
                        event.preventDefault;
208
                        event.stopPropagation();
209
                    }
210

    
211
                    $scope.$apply();
212
                } else if(event.which == 38) {
213
                    if ($scope.currentIndex >= 1) {
214
                        $scope.currentIndex --;
215
                        $scope.$apply();
216
                        event.preventDefault;
217
                        event.stopPropagation();
218
                    }
219

    
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]);
223
                        $scope.$apply();
224
                        event.preventDefault;
225
                        event.stopPropagation();
226
                    } else {
227
                        $scope.results = [];
228
                        $scope.$apply();
229
                        event.preventDefault;
230
                        event.stopPropagation();
231
                    }
232

    
233
                } else if (event.which == 27) {
234
                    $scope.results = [];
235
                    $scope.showDropdown = false;
236
                    $scope.$apply();
237
                } else if (event.which == 8) {
238
                    $scope.selectedObject = null;
239
                    $scope.$apply();
240
                }
241
            });
242

    
243
        }
244
    };
245
});
246

    
    (1-1/1)