From a362ce1b06a15276b54b89926b13ed9db3b68646 Mon Sep 17 00:00:00 2001 From: Tomas Kirda Date: Thu, 21 Feb 2013 16:25:07 -0600 Subject: [PATCH] Call transformResult on the value returned from the server. Fixes #49 --- readme.md | 23 ++++++++++++--------- spec/autocompleteBehavior.js | 39 ++++++++++++++++++++++++++++++++++++ src/jquery.autocomplete.js | 27 +++++++++++++------------ 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/readme.md b/readme.md index f9f4900..5071619 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ The standard jquery.autocomplete.js file is around 2.7KB when minified via Closu * `serviceUrl`: Server side URL that provides results for suggestions. Optional if local lookup data is provided. * `lookup`: Lookup array for the suggestions. It may be array of strings or `suggestion` object literals. * `suggestion`: An object literal with the following format: `{ value: 'string', data: any }`. - * `lookupFilter`: `function (suggestion, query, queryLowerCase) {}` filter function for local lookups. By default it does partial string match (case insensitive). + * `lookupFilter`: `function (suggestion, query, queryLowerCase) {}` filter function for local lookups. By default it does partial string match (case insensitive). * `onSelect`: `function (suggestion) {}` Callback function invoked when user selects suggestion from the list. `this` inside callback refers to input HtmlElement. * `minChars`: Minimum number of characters required to trigger autosuggest. Default: `1`. @@ -34,10 +34,10 @@ The standard jquery.autocomplete.js file is around 2.7KB when minified via Closu * `onSearchComplete`: `function (query) {}` called after ajax response is processed. `this` is bound to input element. * `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. - * `transformResult`: `function(response) {}` called after the result of the query is ready. Converts the result into response.suggestions format. - * `autoSelectFirst`: if set to `true`, first item will be selected when showing suggestions. Default value `false`. - * `appendTo`: container where suggestions will be appended. Default value `body`. Can be jQuery object, selector or html element. Make sure to set `position: absolute` or `position: relative` for that element. - * `dataType`: type of data returned from server. Either 'text' (default) or 'jsonp', which will cause the autocomplete to use jsonp. You may return a json object in your callback when using jsonp. + * `transformResult`: `function(response, originalQuery) {}` called after the result of the query is ready. Converts the result into response.suggestions format. + * `autoSelectFirst`: if set to `true`, first item will be selected when showing suggestions. Default value `false`. + * `appendTo`: container where suggestions will be appended. Default value `body`. Can be jQuery object, selector or html element. Make sure to set `position: absolute` or `position: relative` for that element. + * `dataType`: type of data returned from server. Either 'text' (default) or 'jsonp', which will cause the autocomplete to use jsonp. You may return a json object in your callback when using jsonp. ##Usage @@ -115,13 +115,16 @@ you can supply the "paramName" and "transformResult" options: $('#autocomplete').autocomplete({ paramName: 'searchString', - transformResult: function(response) { - return $.map(response.myData, function(dataItem) { - return {value: dataItem.valueField, data: dataItem.dataField}; - }); + transformResult: function(response, originalQuery) { + return { + query: originalQuery, + suggestions: $.map(response.myData, function(dataItem) { + return { value: dataItem.valueField, data: dataItem.dataField }; + }) + }; } }) - + Important: query value must match original value in the input field, otherwise suggestions will not be displayed. diff --git a/spec/autocompleteBehavior.js b/spec/autocompleteBehavior.js index 0d132f2..93e1f3a 100644 --- a/spec/autocompleteBehavior.js +++ b/spec/autocompleteBehavior.js @@ -171,6 +171,45 @@ describe('Autocomplete', function () { }); }); + it('Should transform results', function () { + var input = document.createElement('input'), + ajaxExecuted = false, + url = '/test-transform', + autocomplete = new $.Autocomplete(input, { + serviceUrl: url, + transformResult: function (result, query) { + return { + query: query, + suggestions: $.map(result.split(','), function (item) { + return { value: item, data: null }; + }) + }; + } + }); + + $.mockjax({ + url: url, + responseTime: 50, + response: function () { + ajaxExecuted = true; + this.responseText = 'Andora,Angola,Argentina'; + } + }); + + input.value = 'A'; + autocomplete.onValueChange(); + + waitsFor(function () { + return ajaxExecuted; + }, 'Ajax call never completed.', 100); + + runs(function () { + expect(ajaxExecuted).toBe(true); + expect(autocomplete.suggestions.length).toBe(3); + expect(autocomplete.suggestions[0].value).toBe('Andora'); + }); + }); + it('Should should not preventDefault when tabDisabled is set to false', function () { var input = document.createElement('input'), autocomplete = new $.Autocomplete(input, { diff --git a/src/jquery.autocomplete.js b/src/jquery.autocomplete.js index 61be06c..f927766 100644 --- a/src/jquery.autocomplete.js +++ b/src/jquery.autocomplete.js @@ -94,8 +94,8 @@ return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1; }, paramName: 'query', - transformResult: function (response) { - return response.suggestions; + transformResult: function (response, originalQuery) { + return typeof response === 'string' ? $.parseJSON(response) : response; } }; @@ -408,8 +408,8 @@ data: options.params, type: options.type, dataType: options.dataType - }).done(function (txt) { - that.processResponse(txt); + }).done(function (data) { + that.processResponse(data, q); options.onSearchComplete.call(that.element, q); }); } @@ -475,23 +475,24 @@ return suggestions; }, - processResponse: function (text) { + processResponse: function (response, originalQuery) { var that = this, - response = typeof text == 'string' ? $.parseJSON(text) : text; + options = that.options, + result = that.options.transformResult(response, originalQuery); - response.suggestions = that.verifySuggestionsFormat(that.options.transformResult(response)); + result.suggestions = that.verifySuggestionsFormat(result.suggestions); // Cache results if cache is not disabled: - if (!that.options.noCache) { - that.cachedResponse[response[that.options.paramName]] = response; - if (response.suggestions.length === 0) { - that.badQueries.push(response[that.options.paramName]); + if (!options.noCache) { + that.cachedResponse[result[options.paramName]] = result; + if (result.suggestions.length === 0) { + that.badQueries.push(result[options.paramName]); } } // Display suggestions only if returned query matches current value: - if (response[that.options.paramName] === that.getQuery(that.currentValue)) { - that.suggestions = response.suggestions; + if (result[options.paramName] === that.getQuery(that.currentValue)) { + that.suggestions = result.suggestions; that.suggest(); } },