2
0
mirror of https://github.com/devbridge/jQuery-Autocomplete.git synced 2024-11-22 12:55:12 +00:00

Merge pull request #138 from macool/newOnSearchComplete

`onSearchComplete` receives `suggestions` as parameter
This commit is contained in:
Tomas Kirda 2014-01-05 16:27:57 -08:00
commit 51a2b6b657
3 changed files with 79 additions and 15 deletions

View File

@ -32,10 +32,11 @@ The standard jquery.autocomplete.js file is around 2.7KB when minified via Closu
* `type`: Ajax request type to get suggestions. Default: `GET`. * `type`: Ajax request type to get suggestions. Default: `GET`.
* `noCache`: Boolean value indicating whether to cache suggestion results. Default `false`. * `noCache`: Boolean value indicating whether to cache suggestion results. Default `false`.
* `onSearchStart`: `function (query) {}` called before ajax request. `this` is bound to input element. * `onSearchStart`: `function (query) {}` called before ajax request. `this` is bound to input element.
* `onSearchComplete`: `function (query) {}` called after ajax response is processed. `this` is bound to input element. * `onSearchComplete`: `function (query, suggestions) {}` called after ajax response is processed. `this` is bound to input element. `suggestions` is an array containing the results.
* `onSearchError`: `function (query, jqXHR, textStatus, errorThrown) {}` called if ajax request fails. `this` is bound to input element. * `onSearchError`: `function (query, jqXHR, textStatus, errorThrown) {}` called if ajax request fails. `this` is bound to input element.
* `onInvalidateSelection`: `function () {}` called when input is altered after selection has been made. `this` is bound to input element. * `onInvalidateSelection`: `function () {}` called when input is altered after selection has been made. `this` is bound to input element.
* `triggerSelectOnValidInput`: Boolean value indicating if `select` should be triggered if it matches suggestion. Default `true`. * `triggerSelectOnValidInput`: Boolean value indicating if `select` should be triggered if it matches suggestion. Default `true`.
* `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`.
* `beforeRender`: `function (container) {}` called before displaying the suggestions. You may manipulate suggestions DOM before it is displayed. * `beforeRender`: `function (container) {}` called before displaying the suggestions. You may manipulate suggestions DOM before it is displayed.
* `tabDisabled`: Default `false`. Set to true to leave the cursor in the input field after the user tabs to select a suggestion. * `tabDisabled`: Default `false`. Set to true to leave the cursor in the input field after the user tabs to select a suggestion.
* `paramName`: Default `query`. The name of the request parameter that contains the query. * `paramName`: Default `query`. The name of the request parameter that contains the query.

View File

@ -136,12 +136,15 @@ describe('Autocomplete', function () {
it('Should execute onSearchComplete', function () { it('Should execute onSearchComplete', function () {
var input = document.createElement('input'), var input = document.createElement('input'),
completeQuery, completeQuery,
mockupSuggestion = { value: 'A', data: 'A' },
resultSuggestions,
ajaxExecuted = false, ajaxExecuted = false,
url = '/test-completed', url = '/test-completed',
autocomplete = new $.Autocomplete(input, { autocomplete = new $.Autocomplete(input, {
serviceUrl: url, serviceUrl: url,
onSearchComplete: function (query) { onSearchComplete: function (query, suggestions) {
completeQuery = query; completeQuery = query;
resultSuggestions = suggestions;
} }
}); });
@ -153,7 +156,7 @@ describe('Autocomplete', function () {
var query = settings.data.query, var query = settings.data.query,
response = { response = {
query: query, query: query,
suggestions: [] suggestions: [mockupSuggestion]
}; };
this.responseText = JSON.stringify(response); this.responseText = JSON.stringify(response);
} }
@ -169,6 +172,8 @@ describe('Autocomplete', function () {
runs(function () { runs(function () {
expect(ajaxExecuted).toBe(true); expect(ajaxExecuted).toBe(true);
expect(completeQuery).toBe('A'); expect(completeQuery).toBe('A');
expect(resultSuggestions[0].value).toBe('A');
expect(resultSuggestions[0].data).toBe('A');
}); });
}); });
@ -597,4 +602,56 @@ describe('Autocomplete', function () {
expect(instance.suggestions.length).toBe(limit); expect(instance.suggestions.length).toBe(limit);
}); });
});
it('Should prevent Ajax requests if previous query with matching root failed.', function () {
var input = $('<input />'),
instance,
serviceUrl = '/autocomplete/prevent/ajax',
ajaxCount = 0;
input.autocomplete({
serviceUrl: serviceUrl
});
$.mockjax({
url: serviceUrl,
responseTime: 5,
response: function (settings) {
ajaxCount++;
var response = { suggestions: [] };
this.responseText = JSON.stringify(response);
}
});
input.val('Jam');
instance = input.autocomplete();
instance.onValueChange();
waits(10);
runs(function (){
expect(ajaxCount).toBe(1);
input.val('Jama');
instance.onValueChange();
});
waits(10);
runs(function (){
// Ajax call should not have bee made:
expect(ajaxCount).toBe(1);
// Change setting and continue:
instance.setOptions({ preventBadQueries: false });
input.val('Jamai');
instance.onValueChange();
});
waits(10);
runs(function (){
// Ajax call should have been made:
expect(ajaxCount).toBe(2);
});
});
});

View File

@ -76,6 +76,7 @@
dataType: 'text', dataType: 'text',
currentRequest: null, currentRequest: null,
triggerSelectOnValidInput: true, triggerSelectOnValidInput: true,
preventBadQueries: true,
lookupFilter: function (suggestion, originalQuery, queryLowerCase) { lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1; return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
}, },
@ -473,11 +474,11 @@
that = this, that = this,
options = that.options, options = that.options,
serviceUrl = options.serviceUrl, serviceUrl = options.serviceUrl,
data, params,
cacheKey; cacheKey;
options.params[options.paramName] = q; options.params[options.paramName] = q;
data = options.ignoreParams ? null : options.params; params = options.ignoreParams ? null : options.params;
if (that.isLocal) { if (that.isLocal) {
response = that.getSuggestionsLocal(q); response = that.getSuggestionsLocal(q);
@ -485,7 +486,7 @@
if ($.isFunction(serviceUrl)) { if ($.isFunction(serviceUrl)) {
serviceUrl = serviceUrl.call(that.element, q); serviceUrl = serviceUrl.call(that.element, q);
} }
cacheKey = serviceUrl + '?' + $.param(data || {}); cacheKey = serviceUrl + '?' + $.param(params || {});
response = that.cachedResponse[cacheKey]; response = that.cachedResponse[cacheKey];
} }
@ -501,13 +502,15 @@
} }
that.currentRequest = $.ajax({ that.currentRequest = $.ajax({
url: serviceUrl, url: serviceUrl,
data: data, data: params,
type: options.type, type: options.type,
dataType: options.dataType dataType: options.dataType
}).done(function (data) { }).done(function (data) {
var result;
that.currentRequest = null; that.currentRequest = null;
that.processResponse(data, q, cacheKey); result = options.transformResult(data);
options.onSearchComplete.call(that.element, q); that.processResponse(result, q, cacheKey);
options.onSearchComplete.call(that.element, q, result.suggestions);
}).fail(function (jqXHR, textStatus, errorThrown) { }).fail(function (jqXHR, textStatus, errorThrown) {
options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown); options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
}); });
@ -515,6 +518,10 @@
}, },
isBadQuery: function (q) { isBadQuery: function (q) {
if (!this.options.preventBadQueries){
return false;
}
var badQueries = this.badQueries, var badQueries = this.badQueries,
i = badQueries.length; i = badQueries.length;
@ -637,18 +644,17 @@
return suggestions; return suggestions;
}, },
processResponse: function (response, originalQuery, cacheKey) { processResponse: function (result, originalQuery, cacheKey) {
var that = this, var that = this,
options = that.options, options = that.options;
result = options.transformResult(response, originalQuery);
result.suggestions = that.verifySuggestionsFormat(result.suggestions); result.suggestions = that.verifySuggestionsFormat(result.suggestions);
// Cache results if cache is not disabled: // Cache results if cache is not disabled:
if (!options.noCache) { if (!options.noCache) {
that.cachedResponse[cacheKey] = result; that.cachedResponse[cacheKey] = result;
if (result.suggestions.length === 0) { if (options.preventBadQueries && result.suggestions.length === 0) {
that.badQueries.push(cacheKey); that.badQueries.push(originalQuery);
} }
} }