diff --git a/src/dropdownListModel.ts b/src/dropdownListModel.ts index 3bb93586cc..9768edc298 100644 --- a/src/dropdownListModel.ts +++ b/src/dropdownListModel.ts @@ -18,6 +18,7 @@ export class DropdownListModel extends Base { private _markdownMode = false; private _popupModel: PopupModel; + private filteredItems: Array = undefined; @property({ defaultValue: false }) focused: boolean; private get focusFirstInputSelector(): string { return this.getFocusFirstInputSelector(); @@ -160,12 +161,9 @@ export class DropdownListModel extends Base { }; } const res = new ListModel(visibleItems, _onSelectionChanged, false, undefined, this.question.choicesLazyLoadEnabled ? this.listModelFilterStringChanged : undefined, this.listElementId); - res.setOnTextSearchCallback((text: string, textToSearch: string) => { - const options = { question: this.question, text: text, filter: textToSearch, result: undefined as boolean }; - (this.question.survey as SurveyModel).onItemTextSearch.fire(this.question.survey as SurveyModel, options); - if (options.result !== undefined) return options.result; - - let textInLow = text.toLocaleLowerCase(); + res.setOnTextSearchCallback((item: ItemValue, textToSearch: string) => { + if (this.filteredItems) return this.filteredItems.indexOf(item) >= 0; + let textInLow = item.text.toLocaleLowerCase(); textInLow = settings.comparator.normalizeTextCallback(textInLow, "filter"); const index = textInLow.indexOf(textToSearch.toLocaleLowerCase()); return this.question.searchMode == "startsWith" ? index == 0 : index > -1; @@ -202,7 +200,12 @@ export class DropdownListModel extends Base { this.resetFilterString(); } protected onSetFilterString(): void { + this.filteredItems = undefined; if (!this.filterString && !this.popupModel.isVisible) return; + const options = { question: this.question, items: this.getAvailableItems(), filter: this.filterString, result: undefined as Array }; + (this.question.survey as SurveyModel).onChoicesSearch.fire(this.question.survey as SurveyModel, options); + this.filteredItems = options.result; + if (!!this.filterString && !this.popupModel.isVisible) { this.popupModel.isVisible = true; } diff --git a/src/list.ts b/src/list.ts index d93fc2dcd6..223754eb48 100644 --- a/src/list.ts +++ b/src/list.ts @@ -67,7 +67,7 @@ export class ListModel extends ActionContainer private hasText(item: T, filterStringInLow: string): boolean { if (!filterStringInLow) return true; const text = item.title || ""; - if (this.onTextSearchCallback) return this.onTextSearchCallback(text, filterStringInLow); + if (this.onTextSearchCallback) return this.onTextSearchCallback(item, filterStringInLow); let textInLow = text.toLocaleLowerCase(); textInLow = settings.comparator.normalizeTextCallback(textInLow, "filter"); return textInLow.indexOf(filterStringInLow.toLocaleLowerCase()) > -1; @@ -112,11 +112,11 @@ export class ListModel extends ActionContainer this.setItems(items); this.selectedItem = selectedItem; } - private onTextSearchCallback: (text: string, textToSearch: string) => boolean; + private onTextSearchCallback: (item: T, textToSearch: string) => boolean; public setOnFilterStringChangedCallback(callback: (text: string) => void) { this.onFilterStringChangedCallback = callback; } - public setOnTextSearchCallback(callback: (text: string, textToSearch: string) => boolean) { + public setOnTextSearchCallback(callback: (item: T, textToSearch: string) => boolean) { this.onTextSearchCallback = callback; } public setItems(items: Array, sortByVisibleIndex = true): void { diff --git a/src/survey-events-api.ts b/src/survey-events-api.ts index 5a44634877..1923c19490 100644 --- a/src/survey-events-api.ts +++ b/src/survey-events-api.ts @@ -611,17 +611,15 @@ export interface ChoicesLazyLoadEvent extends QuestionEventMixin { skip: number; } -export interface ItemTextSearchEvent extends QuestionEventMixin { - /** - * A text... - */ - text: string; +export interface ChoicesSearchEvent extends QuestionEventMixin { /** * A search string used to filter. */ filter: string; - result: boolean; + items: Array; + + result: Array; } export interface GetChoiceDisplayValueEvent extends QuestionEventMixin { diff --git a/src/survey.ts b/src/survey.ts index 91bc5144af..6247b49c82 100644 --- a/src/survey.ts +++ b/src/survey.ts @@ -64,7 +64,7 @@ import { MatrixCellValidateEvent, DynamicPanelModifiedEvent, DynamicPanelRemovingEvent, TimerPanelInfoTextEvent, DynamicPanelItemValueChangedEvent, DynamicPanelGetTabTitleEvent, DynamicPanelCurrentIndexChangedEvent, IsAnswerCorrectEvent, DragDropAllowEvent, ScrollingElementToTopEvent, GetQuestionTitleActionsEvent, GetPanelTitleActionsEvent, GetPageTitleActionsEvent, GetPanelFooterActionsEvent, GetMatrixRowActionsEvent, ElementContentVisibilityChangedEvent, GetExpressionDisplayValueEvent, - ServerValidateQuestionsEvent, MultipleTextItemAddedEvent, MatrixColumnAddedEvent, GetQuestionDisplayValueEvent, PopupVisibleChangedEvent, ItemTextSearchEvent + ServerValidateQuestionsEvent, MultipleTextItemAddedEvent, MatrixColumnAddedEvent, GetQuestionDisplayValueEvent, PopupVisibleChangedEvent, ChoicesSearchEvent } from "./survey-events-api"; import { QuestionMatrixDropdownModelBase } from "./question_matrixdropdownbase"; import { QuestionMatrixDynamicModel } from "./question_matrixdynamic"; @@ -611,7 +611,7 @@ export class SurveyModel extends SurveyElementCore */ public onChoicesLazyLoad: EventBase = this.addEvent(); - public onItemTextSearch: EventBase = this.addEvent(); + public onChoicesSearch: EventBase = this.addEvent(); /** * Use this event to load a display text for the [default choice item](https://surveyjs.io/form-library/documentation/questiondropdownmodel#defaultValue) in [Dropdown](https://surveyjs.io/form-library/documentation/questiondropdownmodel) and [Tag Box](https://surveyjs.io/form-library/documentation/questiontagboxmodel) questions. diff --git a/tests/dropdown_list_model_test.ts b/tests/dropdown_list_model_test.ts index cb7277626c..8708f2b2b8 100644 --- a/tests/dropdown_list_model_test.ts +++ b/tests/dropdown_list_model_test.ts @@ -961,8 +961,8 @@ QUnit.test("DropdownListModel filter event", (assert) => { }] }); - survey.onItemTextSearch.add((sender, options) => { - options.result = options.text.indexOf(options.filter) + options.filter.length == options.text.length; + survey.onChoicesSearch.add((sender, options) => { + options.result = options.items.filter(item => item.text.indexOf(options.filter) + options.filter.length == item.text.length); }); const question = survey.getAllQuestions()[0];