Skip to content

Commit

Permalink
#7868 searchMode property for Tagbox? (#7874)
Browse files Browse the repository at this point in the history
Fixes #7868
  • Loading branch information
novikov82 authored Feb 19, 2024
1 parent 03218c5 commit 99031db
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 8 deletions.
17 changes: 10 additions & 7 deletions src/dropdownListModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ export class DropdownListModel extends Base {
protected getAvailableItems(): Array<ItemValue> {
return this.question.visibleChoices;
}
protected setOnTextSearchCallbackForListModel(listModel: ListModel<ItemValue>) {
listModel.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;
});
}
protected createListModel(): ListModel<ItemValue> {
const visibleItems = this.getAvailableItems();
let _onSelectionChanged = this.onSelectionChanged;
Expand All @@ -163,13 +172,7 @@ export class DropdownListModel extends Base {
};
}
const res = new ListModel<ItemValue>(visibleItems, _onSelectionChanged, false, undefined, this.question.choicesLazyLoadEnabled ? this.listModelFilterStringChanged : undefined, this.listElementId);
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;
});
this.setOnTextSearchCallbackForListModel(res);
res.renderElements = false;
res.forceShowFilter = true;
res.areSameItemsCallback = (item1: IAction, item2: IAction): boolean => {
Expand Down
1 change: 1 addition & 0 deletions src/dropdownMultiSelectListModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class DropdownMultiSelectListModel extends DropdownListModel {
};
}
const res = new MultiSelectListModel<ItemValue>(visibleItems, _onSelectionChanged, false, undefined, this.question.choicesLazyLoadEnabled ? this.listModelFilterStringChanged : undefined, this.listElementId);
this.setOnTextSearchCallbackForListModel(res);
res.forceShowFilter = true;
return res;
}
Expand Down
13 changes: 12 additions & 1 deletion src/question_tagbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ export class QuestionTagboxModel extends QuestionCheckboxModel {
this.dropdownListModel = new DropdownMultiSelectListModel(this);
}
}
/**
* Specifies a comparison operation used to filter the drop-down list. Applies only if [`searchEnabled`](#searchEnabled) is `true`.
*
* Possible values:
*
* - `"contains"` (default)
* - `"startsWith"`
* @see [SurveyModel.onChoicesSearch](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onChoicesSearch)
*/
@property() searchMode: "contains" | "startsWith";

/**
* Specifies whether to display a button that clears the selected value.
Expand Down Expand Up @@ -242,7 +252,8 @@ Serializer.addClass(
{ name: "choicesLazyLoadPageSize:number", default: 25, visible: false },
{ name: "hideSelectedItems:boolean", default: false },
{ name: "closeOnSelect:boolean" },
{ name: "itemComponent", visible: false, default: "" }
{ name: "itemComponent", visible: false, default: "" },
{ name: "searchMode", default: "contains", choices: ["contains", "startsWith"] }
],
function () {
return new QuestionTagboxModel("");
Expand Down
32 changes: 32 additions & 0 deletions tests/question_tagbox_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PopupBaseViewModel } from "../src/popup-view-model";
import { _setIsTouch } from "../src/utils/devices";
import { settings } from "../src/settings";
import { QuestionMatrixDynamicModel } from "../src/question_matrixdynamic";
import { ListModel } from "../src/list";

export default QUnit.module("Tagbox question");

Expand Down Expand Up @@ -1509,4 +1510,35 @@ QUnit.test("Check readOnly tagbox with markdown", function (assert) {

assert.equal(q1.displayValue, "item1 | item2 | item3");
assert.equal(q1.locReadOnlyText.renderedHtml, "item1 | item2 | item3");
});

QUnit.test("Tagbox searchmode filter options", (assert) => {
const survey = new SurveyModel({
questions: [{
type: "tagbox",
name: "question1",
searchEnabled: true,
searchMode: "startsWith",
choices: [
"abc",
"abd",
"cab",
"efg"
]
}]
});
const question = <QuestionTagboxModel>survey.getAllQuestions()[0];
assert.equal(question.searchMode, "startsWith");
const dropdownListModel = question.dropdownListModel;
const list: ListModel = dropdownListModel.popupModel.contentComponentData.model as ListModel;

dropdownListModel.filterString = "ab";
const getfilteredItems = () => list.renderedActions.filter(item => list.isItemVisible(item));

assert.equal(list.renderedActions.length, 4);
assert.equal(getfilteredItems().length, 2);

question.searchMode = "contains";
assert.equal(list.renderedActions.length, 4);
assert.equal(getfilteredItems().length, 3);
});

0 comments on commit 99031db

Please sign in to comment.