diff --git a/dist/jquery.autocomplete.esm.js b/dist/jquery.autocomplete.esm.js
index 5f9570c..b32622e 100644
--- a/dist/jquery.autocomplete.esm.js
+++ b/dist/jquery.autocomplete.esm.js
@@ -399,8 +399,9 @@ var _Autocomplete = class _Autocomplete {
const params = options.ignoreParams ? null : options.params;
if (typeof options.lookup === "function") {
options.lookup(q, (data) => {
- this.suggestions = data.suggestions;
- options.onSearchComplete.call(this.element, q, data.suggestions);
+ const suggestions = this.verifySuggestionsFormat(data.suggestions);
+ this.suggestions = suggestions;
+ options.onSearchComplete.call(this.element, q, suggestions);
this.suggest();
});
return;
@@ -430,6 +431,7 @@ var _Autocomplete = class _Autocomplete {
this.currentRequest = $.ajax(ajaxSettings).done((data) => {
this.currentRequest = null;
const result = options.transformResult(data, q);
+ result.suggestions = this.verifySuggestionsFormat(result.suggestions);
options.onSearchComplete.call(this.element, q, result.suggestions);
this.processResponse(result, q, cacheKey);
}).fail((jqXHR, textStatus, errorThrown) => {
@@ -560,7 +562,9 @@ var _Autocomplete = class _Autocomplete {
if (suggestions.length && typeof suggestions[0] === "string") {
return suggestions.map((value) => ({ value, data: null }));
}
- return suggestions;
+ return suggestions.map(
+ (s) => typeof s.value === "string" ? s : { ...s, value: String(s.value) }
+ );
}
validateOrientation(orientation, fallback) {
const normalized = (orientation || "").trim().toLowerCase();
diff --git a/dist/jquery.autocomplete.js b/dist/jquery.autocomplete.js
index 2e143dc..e1e018e 100644
--- a/dist/jquery.autocomplete.js
+++ b/dist/jquery.autocomplete.js
@@ -407,8 +407,9 @@
const params = options.ignoreParams ? null : options.params;
if (typeof options.lookup === "function") {
options.lookup(q, (data) => {
- this.suggestions = data.suggestions;
- options.onSearchComplete.call(this.element, q, data.suggestions);
+ const suggestions = this.verifySuggestionsFormat(data.suggestions);
+ this.suggestions = suggestions;
+ options.onSearchComplete.call(this.element, q, suggestions);
this.suggest();
});
return;
@@ -438,6 +439,7 @@
this.currentRequest = $2.ajax(ajaxSettings).done((data) => {
this.currentRequest = null;
const result = options.transformResult(data, q);
+ result.suggestions = this.verifySuggestionsFormat(result.suggestions);
options.onSearchComplete.call(this.element, q, result.suggestions);
this.processResponse(result, q, cacheKey);
}).fail((jqXHR, textStatus, errorThrown) => {
@@ -568,7 +570,9 @@
if (suggestions.length && typeof suggestions[0] === "string") {
return suggestions.map((value) => ({ value, data: null }));
}
- return suggestions;
+ return suggestions.map(
+ (s) => typeof s.value === "string" ? s : { ...s, value: String(s.value) }
+ );
}
validateOrientation(orientation, fallback) {
const normalized = (orientation || "").trim().toLowerCase();
diff --git a/dist/jquery.autocomplete.min.js b/dist/jquery.autocomplete.min.js
index 231a9b3..d828068 100644
--- a/dist/jquery.autocomplete.min.js
+++ b/dist/jquery.autocomplete.min.js
@@ -15,6 +15,6 @@
factory(jQuery);
}
})(function ($) {
-"use strict";(()=>{var l=null;function C(r){l=r}var v={escapeRegExChars(r){return r.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode(r){let t=document.createElement("div");return t.className=r,t.style.position="absolute",t.style.display="none",t}},h={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};function x(r,t,e){return r.value.toLowerCase().indexOf(e)!==-1}function T(r){return typeof r=="string"?JSON.parse(r):r}function w(r,t){if(!t)return r.value;let e="("+v.escapeRegExChars(t)+")";return r.value.replace(new RegExp(e,"gi"),"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")}function R(r,t){return'
'+t+"
"}var b=()=>{},A={ajaxSettings:{},autoSelectFirst:!1,appendTo:"body",width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:w,formatGroup:R,zIndex:9999,type:"GET",noCache:!1,onSearchStart:b,onSearchComplete:b,onSearchError:b,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:x,paramName:"query",transformResult:T,showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1};var p=class p{constructor(t,e){this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.cachedResponse={};this.onChangeTimeout=null;this.isLocal=!1;this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"};this.hint=null;this.hintValue="";this.selection=null;this.currentRequest=null;this.element=t,this.el=l(t),this.currentValue=t.value,this.options=l.extend(!0,{},p.defaults,e),this.initialize(),this.setOptions(e)}initialize(){let t=this,e=`.${this.classes.suggestion}`,s=this.classes.selected,i=this.options;this.element.setAttribute("autocomplete","off"),this.$noSuggestionsContainer=l('').html(i.noSuggestionNotice),this.noSuggestionsContainer=this.$noSuggestionsContainer.get(0),this.suggestionsContainer=p.utils.createNode(i.containerClass),this.$container=l(this.suggestionsContainer),this.$container.appendTo(i.appendTo||"body"),i.width!=="auto"&&this.$container.css("width",i.width);let o=this.$container;o.on("mouseover.autocomplete",e,function(){t.activate(l(this).data("index"))}),o.on("click.autocomplete",e,function(){t.select(l(this).data("index"))}),o.on("mouseout.autocomplete",()=>{this.selectedIndex=-1,o.children(`.${s}`).removeClass(s)}),o.on("click.autocomplete",()=>{this.blurTimeoutId!==void 0&&clearTimeout(this.blurTimeoutId)}),this.fixPositionCapture=()=>{this.visible&&this.fixPosition()},l(window).on("resize.autocomplete",this.fixPositionCapture),this.el.on("keydown.autocomplete",n=>this.onKeyPress(n)),this.el.on("keyup.autocomplete",n=>this.onKeyUp(n)),this.el.on("blur.autocomplete",()=>this.onBlur()),this.el.on("focus.autocomplete",()=>this.onFocus()),this.el.on("change.autocomplete",n=>this.onKeyUp(n)),this.el.on("input.autocomplete",n=>this.onKeyUp(n))}onFocus(){this.disabled||(this.fixPosition(),this.el.val().length>=this.options.minChars&&this.onValueChange())}onBlur(){let t=this.options,e=this.getQuery(this.el.val());this.blurTimeoutId=setTimeout(()=>{this.hide(),this.selection&&this.currentValue!==e&&t.onInvalidateSelection?.call(this.element)},200)}abortAjax(){this.currentRequest&&(this.currentRequest.abort(),this.currentRequest=null)}setOptions(t){let e={...this.options,...t};this.isLocal=Array.isArray(e.lookup),this.isLocal&&(e.lookup=this.verifySuggestionsFormat(e.lookup)),e.orientation=this.validateOrientation(e.orientation,"bottom"),this.$container.css({"max-height":`${e.maxHeight}px`,width:`${e.width}px`,"z-index":e.zIndex}),this.options=e}clearCache(){this.cachedResponse={},this.badQueries=[]}clear(){this.clearCache(),this.currentValue="",this.suggestions=[]}disable(){this.disabled=!0,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.abortAjax()}enable(){this.disabled=!1}fixPosition(){let t=this.$container,e=t.parent().get(0);if(e!==document.body&&!this.options.forceFixPosition)return;let s=this.options.orientation,i=t.outerHeight()??0,o=this.el.outerHeight()??0,n=this.el.offset()??{top:0,left:0},a={top:n.top,left:n.left};if(s==="auto"){let u=l(window).height()??0,c=l(window).scrollTop()??0,g=-c+n.top-i,y=c+u-(n.top+o+i);s=Math.max(g,y)===g?"top":"bottom"}if(a.top+=s==="top"?-i:o,e!==document.body&&e!==void 0){let u=t.css("opacity");this.visible||t.css("opacity",0).show();let c=t.offsetParent().offset()??{top:0,left:0};a.top-=c.top,a.top+=e.scrollTop,a.left-=c.left,this.visible||t.css("opacity",u).hide()}this.options.width==="auto"&&(a.width=`${this.el.outerWidth()??0}px`),t.css(a)}isCursorAtEnd(){let t=this.el.val().length,{selectionStart:e}=this.element;return typeof e=="number"?e===t:!0}onKeyPress(t){if(!this.disabled&&!this.visible&&t.which===h.DOWN&&this.currentValue){this.suggest();return}if(!(this.disabled||!this.visible)){switch(t.which){case h.ESC:this.el.val(this.currentValue),this.hide();break;case h.RIGHT:if(this.hint&&this.options.onHint&&this.isCursorAtEnd()){this.selectHint();break}return;case h.TAB:if(this.hint&&this.options.onHint){this.selectHint();return}if(this.selectedIndex===-1){this.hide();return}if(this.select(this.selectedIndex),this.options.tabDisabled===!1)return;break;case h.RETURN:if(this.selectedIndex===-1){this.hide();return}this.select(this.selectedIndex);break;case h.UP:this.moveUp();break;case h.DOWN:this.moveDown();break;default:return}t.stopImmediatePropagation(),t.preventDefault()}}onKeyUp(t){this.disabled||t.which===h.UP||t.which===h.DOWN||(this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue!==this.el.val()&&(this.findBestHint(),this.options.deferRequestBy>0?this.onChangeTimeout=setTimeout(()=>this.onValueChange(),this.options.deferRequestBy):this.onValueChange()))}onValueChange(){if(this.ignoreValueChange){this.ignoreValueChange=!1;return}let t=this.options,e=this.el.val(),s=this.getQuery(e);if(this.selection&&this.currentValue!==s&&(this.selection=null,t.onInvalidateSelection?.call(this.element)),this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue=e,this.selectedIndex=-1,t.triggerSelectOnValidInput&&this.isExactMatch(s)){this.select(0);return}s.lengthi(u,t,s));return{suggestions:o&&a.length>o?a.slice(0,o):a}}getSuggestions(t){let e=this.options,s=e.serviceUrl,i,o;if(e.params[e.paramName]=t,e.onSearchStart.call(this.element,e.params)===!1)return;let n=e.ignoreParams?null:e.params;if(typeof e.lookup=="function"){e.lookup(t,a=>{this.suggestions=a.suggestions,e.onSearchComplete.call(this.element,t,a.suggestions),this.suggest()});return}if(this.isLocal?i=this.getSuggestionsLocal(t):(typeof s=="function"&&(s=s.call(this.element,t)),o=`${s}?${l.param(n??{})}`,i=this.cachedResponse[o]),i&&Array.isArray(i.suggestions))this.suggestions=i.suggestions,e.onSearchComplete.call(this.element,t,i.suggestions),this.suggest();else if(this.isBadQuery(t))e.onSearchComplete.call(this.element,t,[]);else{this.abortAjax();let a={url:s,data:n??void 0,type:e.type,dataType:e.dataType,...e.ajaxSettings};this.currentRequest=l.ajax(a).done(u=>{this.currentRequest=null;let c=e.transformResult(u,t);e.onSearchComplete.call(this.element,t,c.suggestions),this.processResponse(c,t,o)}).fail((u,c,g)=>{e.onSearchError.call(this.element,t,u,c,g)})}}isBadQuery(t){return this.options.preventBadQueries?this.badQueries.some(e=>t.indexOf(e)===0):!1}hide(){this.options.onHide&&this.visible&&this.options.onHide.call(this.element,this.$container),this.visible=!1,this.selectedIndex=-1,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.$container.hide(),this.onHint(null)}groupSuggestionsByCategory(t,e){let s=new Map;for(let i of t){let o=i.data[e],n=s.get(o);n?n.push(i):s.set(o,[i])}return Array.from(s.values()).flat()}suggest(){if(!this.suggestions.length){this.options.showNoSuggestionNotice?this.noSuggestions():this.hide();return}let t=this.options,{groupBy:e,formatResult:s,beforeRender:i}=t,o=this.getQuery(this.currentValue),n=this.classes.suggestion,a=this.classes.selected,u=this.$container;if(t.triggerSelectOnValidInput&&this.isExactMatch(o)){this.select(0);return}e&&(this.suggestions=this.groupSuggestionsByCategory(this.suggestions,e));let c,g=d=>{let f=d.data[e];return c===f?"":(c=f,t.formatGroup(d,c))},y=this.suggestions.map((d,f)=>`${e?g(d):""}${s(d,o,f)}
`).join("");this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),u.html(y),i?.call(this.element,u,this.suggestions),this.fixPosition(),u.show(),t.autoSelectFirst&&(this.selectedIndex=0,u.scrollTop(0),u.children(`.${n}`).first().addClass(a)),this.visible=!0,this.findBestHint()}noSuggestions(){let{beforeRender:t}=this.options,e=this.$container;this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),e.empty().append(this.$noSuggestionsContainer),t?.call(this.element,e,this.suggestions),this.fixPosition(),e.show(),this.visible=!0}adjustContainerWidth(){let{width:t}=this.options;if(t==="auto"){let e=this.el.outerWidth()??0;this.$container.css("width",e>0?e:300)}else t==="flex"&&this.$container.css("width","")}findBestHint(){let t=this.el.val().toLowerCase();if(!t)return;let e=this.suggestions.find(s=>s.value.toLowerCase().indexOf(t)===0)??null;this.onHint(e)}onHint(t){let{onHint:e}=this.options,s=t?this.currentValue+t.value.substr(this.currentValue.length):"";this.hintValue!==s&&(this.hintValue=s,this.hint=t,e?.call(this.element,s))}verifySuggestionsFormat(t){return t.length&&typeof t[0]=="string"?t.map(e=>({value:e,data:null})):t}validateOrientation(t,e){let s=(t||"").trim().toLowerCase();return s==="auto"||s==="top"||s==="bottom"?s:e}processResponse(t,e,s){let i=this.options;t.suggestions=this.verifySuggestionsFormat(t.suggestions),i.noCache||(this.cachedResponse[s]=t,i.preventBadQueries&&!t.suggestions.length&&this.badQueries.push(e)),e===this.getQuery(this.currentValue)&&(this.suggestions=t.suggestions,this.suggest())}activate(t){let e=this.classes.selected,s=this.$container,i=s.find(`.${this.classes.suggestion}`);if(s.find(`.${e}`).removeClass(e),this.selectedIndex=t,this.selectedIndex!==-1&&i.length>this.selectedIndex){let o=i.get(this.selectedIndex);return l(o).addClass(e),o}return null}selectHint(){this.select(this.suggestions.indexOf(this.hint))}select(t){this.hide(),this.onSelect(t)}moveUp(){if(this.selectedIndex!==-1){if(this.selectedIndex===0){this.$container.children(`.${this.classes.suggestion}`).first().removeClass(this.classes.selected),this.selectedIndex=-1,this.ignoreValueChange=!1,this.el.val(this.currentValue),this.findBestHint();return}this.adjustScroll(this.selectedIndex-1)}}moveDown(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)}adjustScroll(t){let e=this.activate(t);if(!e)return;let s=l(e).outerHeight()??0,i=e.offsetTop,o=this.$container,n=o.scrollTop()??0,a=n+this.options.maxHeight-s;ia&&o.scrollTop(i-this.options.maxHeight+s),this.options.preserveInput||(this.ignoreValueChange=!0,this.el.val(this.getValue(this.suggestions[t].value))),this.onHint(null)}onSelect(t){let e=this.options.onSelect,s=this.suggestions[t];this.currentValue=this.getValue(s.value),this.currentValue!==this.el.val()&&!this.options.preserveInput&&this.el.val(this.currentValue),this.onHint(null),this.suggestions=[],this.selection=s,e?.call(this.element,s)}getValue(t){let{delimiter:e}=this.options;if(!e)return t;let s=this.currentValue,i=s.split(e);return i.length===1?t:s.substr(0,s.length-i[i.length-1].length)+t}dispose(){this.el.off(".autocomplete").removeData("autocomplete"),this.fixPositionCapture&&l(window).off("resize.autocomplete",this.fixPositionCapture),this.$container.remove()}};p.defaults=A,p.utils=v;var m=p;var S="autocomplete";function k(r){C(r),r.Autocomplete=m,r.fn.devbridgeAutocomplete=function(t,e){return arguments.length?this.each(function(){let s=r(this),i=s.data(S);typeof t=="string"?i&&typeof i[t]=="function"&&i[t](e):(i&&i.dispose&&i.dispose(),i=new m(this,t),s.data(S,i))}):this.first().data(S)},r.fn.autocomplete||(r.fn.autocomplete=r.fn.devbridgeAutocomplete)}k($);})();
+"use strict";(()=>{var c=null;function C(r){c=r}var v={escapeRegExChars(r){return r.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode(r){let t=document.createElement("div");return t.className=r,t.style.position="absolute",t.style.display="none",t}},h={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};function x(r,t,e){return r.value.toLowerCase().indexOf(e)!==-1}function T(r){return typeof r=="string"?JSON.parse(r):r}function w(r,t){if(!t)return r.value;let e="("+v.escapeRegExChars(t)+")";return r.value.replace(new RegExp(e,"gi"),"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")}function R(r,t){return''+t+"
"}var S=()=>{},A={ajaxSettings:{},autoSelectFirst:!1,appendTo:"body",width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:w,formatGroup:R,zIndex:9999,type:"GET",noCache:!1,onSearchStart:S,onSearchComplete:S,onSearchError:S,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:x,paramName:"query",transformResult:T,showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1};var p=class p{constructor(t,e){this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.cachedResponse={};this.onChangeTimeout=null;this.isLocal=!1;this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"};this.hint=null;this.hintValue="";this.selection=null;this.currentRequest=null;this.element=t,this.el=c(t),this.currentValue=t.value,this.options=c.extend(!0,{},p.defaults,e),this.initialize(),this.setOptions(e)}initialize(){let t=this,e=`.${this.classes.suggestion}`,s=this.classes.selected,i=this.options;this.element.setAttribute("autocomplete","off"),this.$noSuggestionsContainer=c('').html(i.noSuggestionNotice),this.noSuggestionsContainer=this.$noSuggestionsContainer.get(0),this.suggestionsContainer=p.utils.createNode(i.containerClass),this.$container=c(this.suggestionsContainer),this.$container.appendTo(i.appendTo||"body"),i.width!=="auto"&&this.$container.css("width",i.width);let o=this.$container;o.on("mouseover.autocomplete",e,function(){t.activate(c(this).data("index"))}),o.on("click.autocomplete",e,function(){t.select(c(this).data("index"))}),o.on("mouseout.autocomplete",()=>{this.selectedIndex=-1,o.children(`.${s}`).removeClass(s)}),o.on("click.autocomplete",()=>{this.blurTimeoutId!==void 0&&clearTimeout(this.blurTimeoutId)}),this.fixPositionCapture=()=>{this.visible&&this.fixPosition()},c(window).on("resize.autocomplete",this.fixPositionCapture),this.el.on("keydown.autocomplete",n=>this.onKeyPress(n)),this.el.on("keyup.autocomplete",n=>this.onKeyUp(n)),this.el.on("blur.autocomplete",()=>this.onBlur()),this.el.on("focus.autocomplete",()=>this.onFocus()),this.el.on("change.autocomplete",n=>this.onKeyUp(n)),this.el.on("input.autocomplete",n=>this.onKeyUp(n))}onFocus(){this.disabled||(this.fixPosition(),this.el.val().length>=this.options.minChars&&this.onValueChange())}onBlur(){let t=this.options,e=this.getQuery(this.el.val());this.blurTimeoutId=setTimeout(()=>{this.hide(),this.selection&&this.currentValue!==e&&t.onInvalidateSelection?.call(this.element)},200)}abortAjax(){this.currentRequest&&(this.currentRequest.abort(),this.currentRequest=null)}setOptions(t){let e={...this.options,...t};this.isLocal=Array.isArray(e.lookup),this.isLocal&&(e.lookup=this.verifySuggestionsFormat(e.lookup)),e.orientation=this.validateOrientation(e.orientation,"bottom"),this.$container.css({"max-height":`${e.maxHeight}px`,width:`${e.width}px`,"z-index":e.zIndex}),this.options=e}clearCache(){this.cachedResponse={},this.badQueries=[]}clear(){this.clearCache(),this.currentValue="",this.suggestions=[]}disable(){this.disabled=!0,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.abortAjax()}enable(){this.disabled=!1}fixPosition(){let t=this.$container,e=t.parent().get(0);if(e!==document.body&&!this.options.forceFixPosition)return;let s=this.options.orientation,i=t.outerHeight()??0,o=this.el.outerHeight()??0,n=this.el.offset()??{top:0,left:0},a={top:n.top,left:n.left};if(s==="auto"){let l=c(window).height()??0,u=c(window).scrollTop()??0,g=-u+n.top-i,y=u+l-(n.top+o+i);s=Math.max(g,y)===g?"top":"bottom"}if(a.top+=s==="top"?-i:o,e!==document.body&&e!==void 0){let l=t.css("opacity");this.visible||t.css("opacity",0).show();let u=t.offsetParent().offset()??{top:0,left:0};a.top-=u.top,a.top+=e.scrollTop,a.left-=u.left,this.visible||t.css("opacity",l).hide()}this.options.width==="auto"&&(a.width=`${this.el.outerWidth()??0}px`),t.css(a)}isCursorAtEnd(){let t=this.el.val().length,{selectionStart:e}=this.element;return typeof e=="number"?e===t:!0}onKeyPress(t){if(!this.disabled&&!this.visible&&t.which===h.DOWN&&this.currentValue){this.suggest();return}if(!(this.disabled||!this.visible)){switch(t.which){case h.ESC:this.el.val(this.currentValue),this.hide();break;case h.RIGHT:if(this.hint&&this.options.onHint&&this.isCursorAtEnd()){this.selectHint();break}return;case h.TAB:if(this.hint&&this.options.onHint){this.selectHint();return}if(this.selectedIndex===-1){this.hide();return}if(this.select(this.selectedIndex),this.options.tabDisabled===!1)return;break;case h.RETURN:if(this.selectedIndex===-1){this.hide();return}this.select(this.selectedIndex);break;case h.UP:this.moveUp();break;case h.DOWN:this.moveDown();break;default:return}t.stopImmediatePropagation(),t.preventDefault()}}onKeyUp(t){this.disabled||t.which===h.UP||t.which===h.DOWN||(this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue!==this.el.val()&&(this.findBestHint(),this.options.deferRequestBy>0?this.onChangeTimeout=setTimeout(()=>this.onValueChange(),this.options.deferRequestBy):this.onValueChange()))}onValueChange(){if(this.ignoreValueChange){this.ignoreValueChange=!1;return}let t=this.options,e=this.el.val(),s=this.getQuery(e);if(this.selection&&this.currentValue!==s&&(this.selection=null,t.onInvalidateSelection?.call(this.element)),this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue=e,this.selectedIndex=-1,t.triggerSelectOnValidInput&&this.isExactMatch(s)){this.select(0);return}s.lengthi(l,t,s));return{suggestions:o&&a.length>o?a.slice(0,o):a}}getSuggestions(t){let e=this.options,s=e.serviceUrl,i,o;if(e.params[e.paramName]=t,e.onSearchStart.call(this.element,e.params)===!1)return;let n=e.ignoreParams?null:e.params;if(typeof e.lookup=="function"){e.lookup(t,a=>{let l=this.verifySuggestionsFormat(a.suggestions);this.suggestions=l,e.onSearchComplete.call(this.element,t,l),this.suggest()});return}if(this.isLocal?i=this.getSuggestionsLocal(t):(typeof s=="function"&&(s=s.call(this.element,t)),o=`${s}?${c.param(n??{})}`,i=this.cachedResponse[o]),i&&Array.isArray(i.suggestions))this.suggestions=i.suggestions,e.onSearchComplete.call(this.element,t,i.suggestions),this.suggest();else if(this.isBadQuery(t))e.onSearchComplete.call(this.element,t,[]);else{this.abortAjax();let a={url:s,data:n??void 0,type:e.type,dataType:e.dataType,...e.ajaxSettings};this.currentRequest=c.ajax(a).done(l=>{this.currentRequest=null;let u=e.transformResult(l,t);u.suggestions=this.verifySuggestionsFormat(u.suggestions),e.onSearchComplete.call(this.element,t,u.suggestions),this.processResponse(u,t,o)}).fail((l,u,g)=>{e.onSearchError.call(this.element,t,l,u,g)})}}isBadQuery(t){return this.options.preventBadQueries?this.badQueries.some(e=>t.indexOf(e)===0):!1}hide(){this.options.onHide&&this.visible&&this.options.onHide.call(this.element,this.$container),this.visible=!1,this.selectedIndex=-1,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.$container.hide(),this.onHint(null)}groupSuggestionsByCategory(t,e){let s=new Map;for(let i of t){let o=i.data[e],n=s.get(o);n?n.push(i):s.set(o,[i])}return Array.from(s.values()).flat()}suggest(){if(!this.suggestions.length){this.options.showNoSuggestionNotice?this.noSuggestions():this.hide();return}let t=this.options,{groupBy:e,formatResult:s,beforeRender:i}=t,o=this.getQuery(this.currentValue),n=this.classes.suggestion,a=this.classes.selected,l=this.$container;if(t.triggerSelectOnValidInput&&this.isExactMatch(o)){this.select(0);return}e&&(this.suggestions=this.groupSuggestionsByCategory(this.suggestions,e));let u,g=d=>{let f=d.data[e];return u===f?"":(u=f,t.formatGroup(d,u))},y=this.suggestions.map((d,f)=>`${e?g(d):""}${s(d,o,f)}
`).join("");this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),l.html(y),i?.call(this.element,l,this.suggestions),this.fixPosition(),l.show(),t.autoSelectFirst&&(this.selectedIndex=0,l.scrollTop(0),l.children(`.${n}`).first().addClass(a)),this.visible=!0,this.findBestHint()}noSuggestions(){let{beforeRender:t}=this.options,e=this.$container;this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),e.empty().append(this.$noSuggestionsContainer),t?.call(this.element,e,this.suggestions),this.fixPosition(),e.show(),this.visible=!0}adjustContainerWidth(){let{width:t}=this.options;if(t==="auto"){let e=this.el.outerWidth()??0;this.$container.css("width",e>0?e:300)}else t==="flex"&&this.$container.css("width","")}findBestHint(){let t=this.el.val().toLowerCase();if(!t)return;let e=this.suggestions.find(s=>s.value.toLowerCase().indexOf(t)===0)??null;this.onHint(e)}onHint(t){let{onHint:e}=this.options,s=t?this.currentValue+t.value.substr(this.currentValue.length):"";this.hintValue!==s&&(this.hintValue=s,this.hint=t,e?.call(this.element,s))}verifySuggestionsFormat(t){return t.length&&typeof t[0]=="string"?t.map(e=>({value:e,data:null})):t.map(e=>typeof e.value=="string"?e:{...e,value:String(e.value)})}validateOrientation(t,e){let s=(t||"").trim().toLowerCase();return s==="auto"||s==="top"||s==="bottom"?s:e}processResponse(t,e,s){let i=this.options;t.suggestions=this.verifySuggestionsFormat(t.suggestions),i.noCache||(this.cachedResponse[s]=t,i.preventBadQueries&&!t.suggestions.length&&this.badQueries.push(e)),e===this.getQuery(this.currentValue)&&(this.suggestions=t.suggestions,this.suggest())}activate(t){let e=this.classes.selected,s=this.$container,i=s.find(`.${this.classes.suggestion}`);if(s.find(`.${e}`).removeClass(e),this.selectedIndex=t,this.selectedIndex!==-1&&i.length>this.selectedIndex){let o=i.get(this.selectedIndex);return c(o).addClass(e),o}return null}selectHint(){this.select(this.suggestions.indexOf(this.hint))}select(t){this.hide(),this.onSelect(t)}moveUp(){if(this.selectedIndex!==-1){if(this.selectedIndex===0){this.$container.children(`.${this.classes.suggestion}`).first().removeClass(this.classes.selected),this.selectedIndex=-1,this.ignoreValueChange=!1,this.el.val(this.currentValue),this.findBestHint();return}this.adjustScroll(this.selectedIndex-1)}}moveDown(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)}adjustScroll(t){let e=this.activate(t);if(!e)return;let s=c(e).outerHeight()??0,i=e.offsetTop,o=this.$container,n=o.scrollTop()??0,a=n+this.options.maxHeight-s;ia&&o.scrollTop(i-this.options.maxHeight+s),this.options.preserveInput||(this.ignoreValueChange=!0,this.el.val(this.getValue(this.suggestions[t].value))),this.onHint(null)}onSelect(t){let e=this.options.onSelect,s=this.suggestions[t];this.currentValue=this.getValue(s.value),this.currentValue!==this.el.val()&&!this.options.preserveInput&&this.el.val(this.currentValue),this.onHint(null),this.suggestions=[],this.selection=s,e?.call(this.element,s)}getValue(t){let{delimiter:e}=this.options;if(!e)return t;let s=this.currentValue,i=s.split(e);return i.length===1?t:s.substr(0,s.length-i[i.length-1].length)+t}dispose(){this.el.off(".autocomplete").removeData("autocomplete"),this.fixPositionCapture&&c(window).off("resize.autocomplete",this.fixPositionCapture),this.$container.remove()}};p.defaults=A,p.utils=v;var m=p;var b="autocomplete";function k(r){C(r),r.Autocomplete=m,r.fn.devbridgeAutocomplete=function(t,e){return arguments.length?this.each(function(){let s=r(this),i=s.data(b);typeof t=="string"?i&&typeof i[t]=="function"&&i[t](e):(i&&i.dispose&&i.dispose(),i=new m(this,t),s.data(b,i))}):this.first().data(b)},r.fn.autocomplete||(r.fn.autocomplete=r.fn.devbridgeAutocomplete)}k($);})();
});
diff --git a/src/Autocomplete.ts b/src/Autocomplete.ts
index e23eb90..0054222 100644
--- a/src/Autocomplete.ts
+++ b/src/Autocomplete.ts
@@ -415,10 +415,11 @@ export class Autocomplete {
if (typeof options.lookup === "function") {
(options.lookup as LookupCallback)(q, (data) => {
- this.suggestions = data.suggestions;
+ const suggestions = this.verifySuggestionsFormat(data.suggestions);
+ this.suggestions = suggestions;
// Fire onSearchComplete before suggest() so consumers see
// "search complete" before any auto-select fires onSelect.
- options.onSearchComplete.call(this.element, q, data.suggestions);
+ options.onSearchComplete.call(this.element, q, suggestions);
this.suggest();
});
return;
@@ -453,6 +454,7 @@ export class Autocomplete {
.done((data) => {
this.currentRequest = null;
const result = options.transformResult(data, q);
+ result.suggestions = this.verifySuggestionsFormat(result.suggestions);
options.onSearchComplete.call(this.element, q, result.suggestions);
this.processResponse(result, q, cacheKey!);
})
@@ -622,7 +624,11 @@ export class Autocomplete {
if (suggestions.length && typeof suggestions[0] === "string") {
return (suggestions as string[]).map((value) => ({ value, data: null }));
}
- return suggestions as Suggestion[];
+ // Coerce non-string `value` so downstream string methods (toLowerCase,
+ // replace, substr, indexOf) don't throw on numeric or other types.
+ return (suggestions as Suggestion[]).map((s) =>
+ typeof s.value === "string" ? s : { ...s, value: String(s.value) }
+ );
}
validateOrientation(orientation: string | undefined, fallback: Orientation): Orientation {
diff --git a/test/autocomplete.test.js b/test/autocomplete.test.js
index fd183d7..b7751dd 100644
--- a/test/autocomplete.test.js
+++ b/test/autocomplete.test.js
@@ -708,6 +708,47 @@ describe("Autocomplete", () => {
});
});
+describe("Autocomplete non-string suggestion values", () => {
+ afterEach(() => {
+ $(".autocomplete-suggestions").remove();
+ });
+
+ it("coerces numeric value from a local lookup so render does not throw", () => {
+ const input = document.createElement("input");
+ const autocomplete = new $.Autocomplete(input, {
+ lookup: [{ value: 12345, data: "n" }],
+ triggerSelectOnValidInput: false,
+ });
+
+ input.value = "1";
+ expect(() => autocomplete.onValueChange()).not.toThrow();
+
+ expect(typeof autocomplete.suggestions[0].value).toBe("string");
+ expect(autocomplete.suggestions[0].value).toBe("12345");
+ });
+
+ it("coerces numeric value from a function lookup callback", () => {
+ const input = document.createElement("input");
+ let completedValueType;
+ let selectedValueType;
+ const autocomplete = new $.Autocomplete(input, {
+ lookup: (_q, done) => done({ suggestions: [{ value: 42, data: "n" }] }),
+ onSearchComplete: (_q, suggestions) => {
+ completedValueType = typeof suggestions[0].value;
+ },
+ onSelect: (suggestion) => {
+ selectedValueType = typeof suggestion.value;
+ },
+ });
+
+ input.value = "42";
+ autocomplete.onValueChange();
+
+ expect(completedValueType).toBe("string");
+ expect(selectedValueType).toBe("string");
+ });
+});
+
describe("Autocomplete event ordering", () => {
afterEach(() => {
$(".autocomplete-suggestions").remove();