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

fix: ensure only selected items are shown when readonly (#6814) (CP: 24.2) #6820

Merged
merged 1 commit into from
Nov 21, 2023
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
36 changes: 28 additions & 8 deletions packages/combo-box/src/vaadin-combo-box-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ export const ComboBoxMixin = (subclass) =>
observer: '_toggleElementChanged',
},

/**
* Set of items to be rendered in the dropdown.
* @protected
*/
_dropdownItems: {
type: Array,
},

/** @private */
_closeOnBlurIsPrevented: Boolean,

Expand All @@ -251,8 +259,8 @@ export const ComboBoxMixin = (subclass) =>
static get observers() {
return [
'_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
'_openedOrItemsChanged(opened, filteredItems, loading)',
'_updateScroller(_scroller, filteredItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
'_openedOrItemsChanged(opened, _dropdownItems, loading)',
'_updateScroller(_scroller, _dropdownItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
];
}

Expand Down Expand Up @@ -491,7 +499,7 @@ export const ComboBoxMixin = (subclass) =>
this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-opened', { bubbles: true, composed: true }));

this._onOpened();
} else if (wasOpened && this.filteredItems && this.filteredItems.length) {
} else if (wasOpened && this._dropdownItems && this._dropdownItems.length) {
this.close();

this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-closed', { bubbles: true, composed: true }));
Expand Down Expand Up @@ -681,7 +689,7 @@ export const ComboBoxMixin = (subclass) =>
/** @private */
_onArrowDown() {
if (this.opened) {
const items = this.filteredItems;
const items = this._dropdownItems;
if (items) {
this._focusedIndex = Math.min(items.length - 1, this._focusedIndex + 1);
this._prefillFocusedItemLabel();
Expand All @@ -697,7 +705,7 @@ export const ComboBoxMixin = (subclass) =>
if (this._focusedIndex > -1) {
this._focusedIndex = Math.max(0, this._focusedIndex - 1);
} else {
const items = this.filteredItems;
const items = this._dropdownItems;
if (items) {
this._focusedIndex = items.length - 1;
}
Expand All @@ -712,7 +720,7 @@ export const ComboBoxMixin = (subclass) =>
/** @private */
_prefillFocusedItemLabel() {
if (this._focusedIndex > -1) {
const focusedItem = this.filteredItems[this._focusedIndex];
const focusedItem = this._dropdownItems[this._focusedIndex];
this._inputElementValue = this._getItemLabel(focusedItem);
this._markAllSelectionRange();
}
Expand Down Expand Up @@ -885,7 +893,7 @@ export const ComboBoxMixin = (subclass) =>
/** @private */
_commitValue() {
if (this._focusedIndex > -1) {
const focusedItem = this.filteredItems[this._focusedIndex];
const focusedItem = this._dropdownItems[this._focusedIndex];
if (this.selectedItem !== focusedItem) {
this.selectedItem = focusedItem;
}
Expand All @@ -900,7 +908,7 @@ export const ComboBoxMixin = (subclass) =>
}
} else {
// Try to find an item which label matches the input value.
const items = [this.selectedItem, ...(this.filteredItems || [])];
const items = [this.selectedItem, ...(this._dropdownItems || [])];
const itemMatchingInputValue = items[this.__getItemIndexByLabel(items, this._inputElementValue)];

if (
Expand Down Expand Up @@ -1115,6 +1123,8 @@ export const ComboBoxMixin = (subclass) =>

/** @private */
_filteredItemsChanged(filteredItems, oldFilteredItems) {
this._setDropdownItems(filteredItems);

// Store the currently focused item if any. The focused index preserves
// in the case when more filtered items are loading but it is reset
// when the user types in a filter query.
Expand Down Expand Up @@ -1175,6 +1185,16 @@ export const ComboBoxMixin = (subclass) =>
}
}

/**
* Provide items to be rendered in the dropdown.
* Override this method to show custom items.
*
* @protected
*/
_setDropdownItems(items) {
this._dropdownItems = items;
}

/** @private */
_getItemElements() {
return Array.from(this._scroller.querySelectorAll(`${this._tagNamePrefix}-item`));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
this._toggleElement = this.querySelector('.toggle-button');
}

/**
* Override combo-box method to group selected
* items at the top of the overlay.
*
* @protected
* @override
*/
_setDropdownItems(items) {
if (this.readonly) {
this._dropdownItems = this.selectedItems;
return;
}

this._dropdownItems = items;
}

/**
* Override combo-box method to set correct owner for using by item renderers.
* This needs to be done before the scroller gets added to the DOM to ensure
Expand Down
11 changes: 11 additions & 0 deletions packages/multi-select-combo-box/test/readonly.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,17 @@ describe('readonly', () => {
expect(items[2].textContent).to.equal('lemon');
expect(items[3].textContent).to.equal('orange');
});

it('should render selected items in the dropdown when size is set', async () => {
inputElement.click();
// Wait for the async data provider timeout
await aTimeout(0);
comboBox.size = 4;
const items = document.querySelectorAll('vaadin-multi-select-combo-box-item');
expect(items.length).to.equal(2);
expect(items[0].textContent).to.equal('apple');
expect(items[1].textContent).to.equal('orange');
});
});

describe('dataProvider is set after selectedItems', () => {
Expand Down