Skip to content

Commit

Permalink
fix: ensure only selected items are shown when readonly (#6814) (#6820)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan authored Nov 21, 2023
1 parent 1a6fcc5 commit f06eff8
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 8 deletions.
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

0 comments on commit f06eff8

Please sign in to comment.