Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

max selected choices not work tagbox with lazy loading #7204

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,8 +564,9 @@ export class Base {
!!this.arraysInfo &&
(!val || Array.isArray(val))
) {
if (this.isTwoValueEquals(oldValue, val)) return;
this.setArrayPropertyDirectly(name, val);
if (!this.isTwoValueEquals(oldValue, val)) {
this.setArrayPropertyDirectly(name, val);
}
} else {
this.setPropertyValueDirectly(name, val);
if (!this.isDisposedValue && !this.isTwoValueEquals(oldValue, val)) {
Expand Down
9 changes: 6 additions & 3 deletions src/question_baseselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,15 +864,18 @@ export class QuestionSelectBase extends Question {
}
return res;
}
protected updateVisibleChoices() {
if (this.isLoadingFromJson) return;
protected updateVisibleChoices(): void {
if (this.isLoadingFromJson || this.isDisposed) return;
var newValue = new Array<ItemValue>();
var calcValue = this.calcVisibleChoices();
if (!calcValue) calcValue = [];
for (var i = 0; i < calcValue.length; i++) {
newValue.push(calcValue[i]);
}
this.setPropertyValue("visibleChoices", newValue);
const oldValue = this.visibleChoices;
if(!this.isTwoValueEquals(oldValue, newValue) || this.choicesLazyLoadEnabled) {
this.setArrayPropertyDirectly("visibleChoices", newValue);
}
}
private calcVisibleChoices(): Array<ItemValue> {
if (this.canUseFilteredChoices()) return this.getFilteredChoices();
Expand Down
127 changes: 127 additions & 0 deletions tests/question_tagbox_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1320,3 +1320,130 @@ QUnit.test("question.showClearButton", assert => {
assert.equal(q.showClearButton, true, "Creator V2");
settings.supportCreatorV2 = false;
});
QUnit.test("lazy loading: maxSelectedChoices limit stops working if you clear the value", assert => {
const done1 = assert.async();
const done2 = assert.async();
const json = {
questions: [{
"type": "tagbox",
"name": "q1",
"defaultValue": [1],
"choicesLazyLoadEnabled": true,
"choicesLazyLoadPageSize": 30,
"maxSelectedChoices": 2
}]
};
const survey = new SurveyModel(json);
survey.onChoicesLazyLoad.add(callback);

const question = <QuestionTagboxModel>survey.getAllQuestions()[0];
const dropdownListModel = question.dropdownListModel;
const list: MultiSelectListModel = dropdownListModel.popupModel.contentComponentData.model as MultiSelectListModel;
assert.equal(question.choicesLazyLoadEnabled, true);
assert.equal(question.choices.length, 0);

question.dropdownListModel.popupModel.toggleVisibility();
setTimeout(() => {
assert.deepEqual(question.value, [1]);
assert.equal(question.choices.length, 30);
for(let index = 0; index < list.actions.length - 1; index++) {
assert.ok(list.actions[index].enabled, list.actions[index].id + " is enabled before clear");
}

list.onItemClick(list.actions[1]);
assert.deepEqual(question.value, [1, 2]);
assert.ok(list.actions[0].enabled, "action 1 is enabled before clear");
assert.ok(list.actions[1].enabled, "action 2 is enabled before clear");
for(let index = 2; index < list.actions.length - 1; index++) {
assert.notOk(list.actions[index].enabled, list.actions[index].id + " is disabled before clear");
}
question.dropdownListModel.popupModel.isVisible = false;
question.dropdownListModel.onClear({
keyCode: 0,
preventDefault: () => { },
stopPropagation: () => { }
});

question.dropdownListModel.popupModel.toggleVisibility();
setTimeout(() => {
assert.deepEqual(question.value, [], "question value is empty");
list.onItemClick(list.actions[0]);
assert.deepEqual(question.value, [1], "question value is [1]");

for(let index = 0; index < list.actions.length - 1; index++) {
assert.ok(list.actions[index].enabled, list.actions[index].id + " is enabled after clear");
}

list.onItemClick(list.actions[1]);
assert.deepEqual(question.value, [1, 2], "question value is [1, 2] after clear");
assert.ok(list.actions[0].enabled, "action 1 is enabled after clear");
assert.ok(list.actions[1].enabled, "action 2 is enabled after clear");
for(let index = 2; index < list.actions.length - 1; index++) {
assert.notOk(list.actions[index].enabled, list.actions[index].id + " is disabled after clear");
}

done2();
}, onChoicesLazyLoadCallbackTimeOut + callbackTimeOutDelta);

done1();
}, onChoicesLazyLoadCallbackTimeOut + callbackTimeOutDelta);
});
QUnit.test("lazy loading & maxSelectedChoices: Items remains disabled when unselecting choices within a drop-down list", assert => {
const done1 = assert.async();
const done2 = assert.async();
const json = {
questions: [{
"type": "tagbox",
"name": "q1",
"defaultValue": [1],
"choicesLazyLoadEnabled": true,
"choicesLazyLoadPageSize": 30,
"maxSelectedChoices": 2
}]
};
const survey = new SurveyModel(json);
survey.onChoicesLazyLoad.add(callback);

const question = <QuestionTagboxModel>survey.getAllQuestions()[0];
const dropdownListModel = question.dropdownListModel;
const list: MultiSelectListModel = dropdownListModel.popupModel.contentComponentData.model as MultiSelectListModel;
assert.equal(question.choicesLazyLoadEnabled, true);
assert.equal(question.choices.length, 0);

question.dropdownListModel.popupModel.toggleVisibility();
setTimeout(() => {
assert.deepEqual(question.value, [1]);
assert.equal(question.choices.length, 30);
for(let index = 0; index < list.actions.length - 1; index++) {
assert.ok(list.actions[index].enabled, list.actions[index].id + " is enabled before unselecting choice");
}

list.onItemClick(list.actions[1]);
assert.deepEqual(question.value, [1, 2]);
assert.ok(list.actions[0].enabled, "action 1 is enabled before unselecting choice");
assert.ok(list.actions[1].enabled, "action 2 is enabled before unselecting choice");
for(let index = 2; index < list.actions.length - 1; index++) {
assert.notOk(list.actions[index].enabled, list.actions[index].id + " is disabled before unselecting choice");
}
question.dropdownListModel.popupModel.isVisible = false;
question.dropdownListModel.popupModel.toggleVisibility();
setTimeout(() => {
assert.deepEqual(question.value, [1, 2], "question value is [1, 2]");
assert.ok(list.actions[0].enabled, "action 1 is enabled");
assert.ok(list.actions[1].enabled, "action 2 is enabled");
for(let index = 2; index < list.actions.length - 1; index++) {
assert.notOk(list.actions[index].enabled, list.actions[index].id + " is disabled");
}

list.onItemClick(list.actions[1]);
assert.deepEqual(question.value, [1], "question value is [1]");
for(let index = 0; index < list.actions.length - 1; index++) {
assert.ok(list.actions[index].enabled, list.actions[index].id + " is enabled after unselecting choice");
}

done2();
}, onChoicesLazyLoadCallbackTimeOut + callbackTimeOutDelta);

done1();
}, onChoicesLazyLoadCallbackTimeOut + callbackTimeOutDelta);
});