Skip to content

Commit 51a2b6b

Browse files
author
Tomas Kirda
committed
Merge pull request #138 from macool/newOnSearchComplete
`onSearchComplete` receives `suggestions` as parameter
2 parents 4924da0 + 07b32b3 commit 51a2b6b

File tree

3 files changed

+79
-15
lines changed

3 files changed

+79
-15
lines changed

readme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ The standard jquery.autocomplete.js file is around 2.7KB when minified via Closu
3232
* `type`: Ajax request type to get suggestions. Default: `GET`.
3333
* `noCache`: Boolean value indicating whether to cache suggestion results. Default `false`.
3434
* `onSearchStart`: `function (query) {}` called before ajax request. `this` is bound to input element.
35-
* `onSearchComplete`: `function (query) {}` called after ajax response is processed. `this` is bound to input element.
35+
* `onSearchComplete`: `function (query, suggestions) {}` called after ajax response is processed. `this` is bound to input element. `suggestions` is an array containing the results.
3636
* `onSearchError`: `function (query, jqXHR, textStatus, errorThrown) {}` called if ajax request fails. `this` is bound to input element.
3737
* `onInvalidateSelection`: `function () {}` called when input is altered after selection has been made. `this` is bound to input element.
3838
* `triggerSelectOnValidInput`: Boolean value indicating if `select` should be triggered if it matches suggestion. Default `true`.
39+
* `preventBadQueries`: Boolean value indicating if it shoud prevent future ajax requests for queries with the same root if no results were returned. E.g. if `Jam` returns no suggestions, it will not fire for any future query that starts with `Jam`. Default `true`.
3940
* `beforeRender`: `function (container) {}` called before displaying the suggestions. You may manipulate suggestions DOM before it is displayed.
4041
* `tabDisabled`: Default `false`. Set to true to leave the cursor in the input field after the user tabs to select a suggestion.
4142
* `paramName`: Default `query`. The name of the request parameter that contains the query.

spec/autocompleteBehavior.js

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,15 @@ describe('Autocomplete', function () {
136136
it('Should execute onSearchComplete', function () {
137137
var input = document.createElement('input'),
138138
completeQuery,
139+
mockupSuggestion = { value: 'A', data: 'A' },
140+
resultSuggestions,
139141
ajaxExecuted = false,
140142
url = '/test-completed',
141143
autocomplete = new $.Autocomplete(input, {
142144
serviceUrl: url,
143-
onSearchComplete: function (query) {
145+
onSearchComplete: function (query, suggestions) {
144146
completeQuery = query;
147+
resultSuggestions = suggestions;
145148
}
146149
});
147150

@@ -153,7 +156,7 @@ describe('Autocomplete', function () {
153156
var query = settings.data.query,
154157
response = {
155158
query: query,
156-
suggestions: []
159+
suggestions: [mockupSuggestion]
157160
};
158161
this.responseText = JSON.stringify(response);
159162
}
@@ -169,6 +172,8 @@ describe('Autocomplete', function () {
169172
runs(function () {
170173
expect(ajaxExecuted).toBe(true);
171174
expect(completeQuery).toBe('A');
175+
expect(resultSuggestions[0].value).toBe('A');
176+
expect(resultSuggestions[0].data).toBe('A');
172177
});
173178
});
174179

@@ -597,4 +602,56 @@ describe('Autocomplete', function () {
597602

598603
expect(instance.suggestions.length).toBe(limit);
599604
});
600-
});
605+
606+
it('Should prevent Ajax requests if previous query with matching root failed.', function () {
607+
var input = $('<input />'),
608+
instance,
609+
serviceUrl = '/autocomplete/prevent/ajax',
610+
ajaxCount = 0;
611+
612+
input.autocomplete({
613+
serviceUrl: serviceUrl
614+
});
615+
616+
$.mockjax({
617+
url: serviceUrl,
618+
responseTime: 5,
619+
response: function (settings) {
620+
ajaxCount++;
621+
var response = { suggestions: [] };
622+
this.responseText = JSON.stringify(response);
623+
}
624+
});
625+
626+
input.val('Jam');
627+
instance = input.autocomplete();
628+
instance.onValueChange();
629+
630+
waits(10);
631+
632+
runs(function (){
633+
expect(ajaxCount).toBe(1);
634+
input.val('Jama');
635+
instance.onValueChange();
636+
});
637+
638+
waits(10);
639+
640+
runs(function (){
641+
// Ajax call should not have bee made:
642+
expect(ajaxCount).toBe(1);
643+
644+
// Change setting and continue:
645+
instance.setOptions({ preventBadQueries: false });
646+
input.val('Jamai');
647+
instance.onValueChange();
648+
});
649+
650+
waits(10);
651+
652+
runs(function (){
653+
// Ajax call should have been made:
654+
expect(ajaxCount).toBe(2);
655+
});
656+
});
657+
});

src/jquery.autocomplete.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
dataType: 'text',
7777
currentRequest: null,
7878
triggerSelectOnValidInput: true,
79+
preventBadQueries: true,
7980
lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
8081
return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
8182
},
@@ -473,19 +474,19 @@
473474
that = this,
474475
options = that.options,
475476
serviceUrl = options.serviceUrl,
476-
data,
477+
params,
477478
cacheKey;
478479

479480
options.params[options.paramName] = q;
480-
data = options.ignoreParams ? null : options.params;
481+
params = options.ignoreParams ? null : options.params;
481482

482483
if (that.isLocal) {
483484
response = that.getSuggestionsLocal(q);
484485
} else {
485486
if ($.isFunction(serviceUrl)) {
486487
serviceUrl = serviceUrl.call(that.element, q);
487488
}
488-
cacheKey = serviceUrl + '?' + $.param(data || {});
489+
cacheKey = serviceUrl + '?' + $.param(params || {});
489490
response = that.cachedResponse[cacheKey];
490491
}
491492

@@ -501,20 +502,26 @@
501502
}
502503
that.currentRequest = $.ajax({
503504
url: serviceUrl,
504-
data: data,
505+
data: params,
505506
type: options.type,
506507
dataType: options.dataType
507508
}).done(function (data) {
509+
var result;
508510
that.currentRequest = null;
509-
that.processResponse(data, q, cacheKey);
510-
options.onSearchComplete.call(that.element, q);
511+
result = options.transformResult(data);
512+
that.processResponse(result, q, cacheKey);
513+
options.onSearchComplete.call(that.element, q, result.suggestions);
511514
}).fail(function (jqXHR, textStatus, errorThrown) {
512515
options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
513516
});
514517
}
515518
},
516519

517520
isBadQuery: function (q) {
521+
if (!this.options.preventBadQueries){
522+
return false;
523+
}
524+
518525
var badQueries = this.badQueries,
519526
i = badQueries.length;
520527

@@ -637,18 +644,17 @@
637644
return suggestions;
638645
},
639646

640-
processResponse: function (response, originalQuery, cacheKey) {
647+
processResponse: function (result, originalQuery, cacheKey) {
641648
var that = this,
642-
options = that.options,
643-
result = options.transformResult(response, originalQuery);
649+
options = that.options;
644650

645651
result.suggestions = that.verifySuggestionsFormat(result.suggestions);
646652

647653
// Cache results if cache is not disabled:
648654
if (!options.noCache) {
649655
that.cachedResponse[cacheKey] = result;
650-
if (result.suggestions.length === 0) {
651-
that.badQueries.push(cacheKey);
656+
if (options.preventBadQueries && result.suggestions.length === 0) {
657+
that.badQueries.push(originalQuery);
652658
}
653659
}
654660

0 commit comments

Comments
 (0)