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

do not render list items if the popup is closed #5745

Merged
merged 9 commits into from
Mar 10, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div [class]="model.cssClasses.emptyContainer" [visible]="model.isEmpty">
<div [class]="model.cssClasses.emptyText" [attr.aria-label]="model.emptyMessage || ''">{{ model.emptyMessage }}</div>
</div>
<ul [class]="model.cssClasses.itemsContainer" role="listbox" [visible]="!model.isEmpty" (mousedown)="onMouseDown($event)" (keydown)="onKeyDown($event)" (mousemove)="onMouseMove($event)">
<ul *ngIf="model.renderElements" [class]="model.cssClasses.itemsContainer" role="listbox" [visible]="!model.isEmpty" (mousedown)="onMouseDown($event)" (keydown)="onKeyDown($event)" (mousemove)="onMouseMove($event)">
<sv-ng-list-item *ngFor="let item of model.renderedActions; trackBy: trackItemBy" [listModel]="model" [model]="item"></sv-ng-list-item>
<!--ko foreach: model.renderedActions -->
<!-- ko component: { name: 'sv-list-item', params: { item: $data, model: $parent.model } } -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class ListComponent extends BaseAngular implements AfterViewInit {
onMouseMove(event: Event): void {
this.model.onMouseMove(event);
}
protected override getPropertiesToUpdateSync(): string[] {
return ["renderElements"];
}
ngAfterViewInit(): void {
if(!!this.listContainerElement?.nativeElement) {
this.model.initListContainerHtmlElement(this.listContainerElement.nativeElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import { AngularComponentFactory } from "../../../component-factory";
})
export class DropdownOptionItemComponent extends BaseAngular {
@Input() item: any;

protected override onModelChanged(): void {
if (!this.item.locText) return;
this.item.locText.onChanged = () => {
this.detectChanges();
};
}
protected getModel() {
return this.item;
}
Expand Down
4 changes: 4 additions & 0 deletions src/dropdownListModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ export class DropdownListModel extends Base {
});
this._popupModel.cssClass = this.popupCssClasses;
this._popupModel.onVisibilityChanged.add((_, option: { isVisible: boolean }) => {
if(option.isVisible) {
this.listModel.renderElements = true;
}
if (option.isVisible && this.question.choicesLazyLoadEnabled) {
this.listModel.actions = [];
this.updateQuestionChoices();
Expand Down Expand Up @@ -134,6 +137,7 @@ export class DropdownListModel extends Base {
};
}
const res = new ListModel<ItemValue>(visibleItems, _onSelectionChanged, false);
res.renderElements = false;
res.areSameItemsCallback = (item1: IAction, item2: IAction): boolean => {
return item1 === item2;
};
Expand Down
2 changes: 2 additions & 0 deletions src/knockout/components/list/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
<div data-bind="css: model.cssClasses.emptyContainer, visible: $data.model.isEmpty">
<div data-bind="css: model.cssClasses.emptyText, text: model.emptyMessage, attr: { 'aria-label': model.emptyMessage }"></div>
</div>
<!-- ko if: $data.model.renderElements -->
<ul role="listbox"
data-bind="css: model.cssClasses.itemsContainer, visible: !$data.model.isEmpty, event: { mousedown: function (data, e) { e.preventDefault(); }, keydown: function(data, e) { $data.model.onKeyDown(event); return true; }, mousemove: function(data, e) { $data.model.onMouseMove(event); return true; } }">
<!-- ko template: { foreach: model.renderedActions, afterRender: $data.afterItemRender } -->
<!-- ko component: { name: 'sv-list-item', params: { item: $data, model: $parent.model } } -->
<!-- /ko -->
<!-- /ko -->
</ul>
<!-- /ko -->
</div>
1 change: 1 addition & 0 deletions src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class ListModel<T extends BaseAction = Action> extends ActionContainer<T>
@property({ defaultValue: false }) hasVerticalScroller: boolean;
@property({ defaultValue: true }) isAllDataLoaded: boolean;
@property({ defaultValue: false }) showSearchClearButton: boolean;
@property({ defaultValue: true }) renderElements: boolean;

public static INDENT: number = 16;
public static MINELEMENTCOUNT: number = 10;
Expand Down
35 changes: 21 additions & 14 deletions src/react/components/list/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,34 @@ export class List extends SurveyElementBase<IListProps, any> {
}
}
renderElement() {
const items = this.renderItems();
const ulStyle = { display: this.model.isEmpty ? "none" : null };
return (
<div className={this.model.cssClasses.root} ref={this.listContainerRef}>
{this.searchElementContent()}
{this.emptyContent()}
<ul
className={this.model.cssClasses.itemsContainer}
style={ulStyle as any}
role="listbox"
onMouseDown={(e) => {
e.preventDefault();
}}
onKeyDown={this.handleKeydown}
onMouseMove={this.handleMouseMove}
>
{items}
</ul>
{this.renderList()}
</div>
);
}
renderList() {
if(!this.model.renderElements) return null;

const items = this.renderItems();
const ulStyle = { display: this.model.isEmpty ? "none" : null };

return (
<ul
className={this.model.cssClasses.itemsContainer}
style={ulStyle as any}
role="listbox"
onMouseDown={(e) => {
e.preventDefault();
}}
onKeyDown={this.handleKeydown}
onMouseMove={this.handleMouseMove}
>
{items}
</ul>);
}
renderItems() {
if (!this.model) {
return null;
Expand Down
1 change: 1 addition & 0 deletions src/vue/components/list/list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<div v-bind:class="model.cssClasses.emptyText" :aria-label="model.emptyMessage">{{ model.emptyMessage }}</div>
</div>
<ul
v-if="model.renderElements"
v-bind:class="model.cssClasses.itemsContainer"
v-show="!model.isEmpty"
role="listbox"
Expand Down
2 changes: 1 addition & 1 deletion testCafe/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const setOptions = ClientFunction((questionName, modValue) => {
};
const q = window["survey"].getQuestionByName(questionName || "car");
mergeOptions(q, modValue);
window["survey"].render();
// window["survey"].render();
});

export const joinElementInnerText = ClientFunction((tagName, index) => {
Expand Down
40 changes: 37 additions & 3 deletions testCafe/questions/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ frameworks.forEach((framework) => {
"Citroen",
];
let checkIntegrity = async (t) => {
await t.click(questionDropdownSelect);
await t.expect(listItems.count).eql(choices.length);
await t.click(questionDropdownSelect);

for (let i = 0; i < choices.length; i++) {
await t
.click(questionDropdownSelect)
Expand Down Expand Up @@ -876,7 +879,7 @@ frameworks.forEach((framework) => {

await t
.expect(popupContainer.visible).notOk()
.expect(listItems.count).eql(27)
.expect(listItems.count).eql(0)
.expect(listItems.filterVisible().count).eql(0)

.pressKey("2")
Expand Down Expand Up @@ -950,7 +953,7 @@ frameworks.forEach((framework) => {

await t
.expect(popupContainer.visible).notOk()
.expect(listItems.count).eql(27)
.expect(listItems.count).eql(0)
.expect(focusedItem.exists).notOk()

.click(questionDropdownSelect)
Expand Down Expand Up @@ -1006,7 +1009,7 @@ frameworks.forEach((framework) => {

await t
.expect(popupContainer.visible).notOk()
.expect(listItems.count).eql(27)
.expect(listItems.count).eql(0)
.expect(listItems.filterVisible().count).eql(0)

.pressKey("2")
Expand Down Expand Up @@ -1504,4 +1507,35 @@ frameworks.forEach((framework) => {

.resizeWindow(1280, 1100);
});

test("do not render list items if the popup is closed", async (t) => {
const json = {
questions: [
{
type: "dropdown",
name: "car",
title: "What car are you driving?",
choices: [
"Ford",
"Vauxhall",
"Volkswagen",
"Nissan",
"Audi",
"Mercedes-Benz",
"BMW",
"Peugeot",
"Toyota",
"Citroen",
],
},
],
};
const listSelector = Selector(".sv-list");
await initSurvey(framework, json);

await t
.expect(listSelector.exists).notOk()
.click(questionDropdownSelect)
.expect(listSelector.exists).ok();
});
});