Skip to content

Commit

Permalink
#7702 Dropdown - Support the Start With search method
Browse files Browse the repository at this point in the history
Fixes #7702
  • Loading branch information
novikov82 committed Jan 26, 2024
1 parent 0d92116 commit bd6072e
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 19 deletions.
15 changes: 9 additions & 6 deletions src/dropdownListModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class DropdownListModel extends Base {

private _markdownMode = false;
private _popupModel: PopupModel;
private filteredItems: Array<ItemValue> = undefined;
@property({ defaultValue: false }) focused: boolean;
private get focusFirstInputSelector(): string {
return this.getFocusFirstInputSelector();
Expand Down Expand Up @@ -160,12 +161,9 @@ export class DropdownListModel extends Base {
};
}
const res = new ListModel<ItemValue>(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;
Expand Down Expand Up @@ -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<ItemValue> };
(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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class ListModel<T extends BaseAction = Action> extends ActionContainer<T>
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;
Expand Down Expand Up @@ -112,11 +112,11 @@ export class ListModel<T extends BaseAction = Action> extends ActionContainer<T>
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<IAction>, sortByVisibleIndex = true): void {
Expand Down
10 changes: 4 additions & 6 deletions src/survey-events-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ItemValue>;

result: Array<ItemValue>;
}

export interface GetChoiceDisplayValueEvent extends QuestionEventMixin {
Expand Down
4 changes: 2 additions & 2 deletions src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -611,7 +611,7 @@ export class SurveyModel extends SurveyElementCore
*/
public onChoicesLazyLoad: EventBase<SurveyModel, ChoicesLazyLoadEvent> = this.addEvent<SurveyModel, ChoicesLazyLoadEvent>();

public onItemTextSearch: EventBase<SurveyModel, ItemTextSearchEvent> = this.addEvent<SurveyModel, ItemTextSearchEvent>();
public onChoicesSearch: EventBase<SurveyModel, ChoicesSearchEvent> = this.addEvent<SurveyModel, ChoicesSearchEvent>();

/**
* 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.
Expand Down
4 changes: 2 additions & 2 deletions tests/dropdown_list_model_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <QuestionDropdownModel>survey.getAllQuestions()[0];
Expand Down

0 comments on commit bd6072e

Please sign in to comment.