@vaadin/combo-box 24.4.0-dev.4b20a0c55.3 → 24.4.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "24.4.0-dev.4b20a0c55.3",
3
+ "version": "24.4.0-rc1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -26,7 +26,9 @@
26
26
  "vaadin-*.d.ts",
27
27
  "vaadin-*.js",
28
28
  "web-types.json",
29
- "web-types.lit.json"
29
+ "web-types.lit.json",
30
+ "!vaadin-lit-*.d.ts",
31
+ "!vaadin-lit-*.js"
30
32
  ],
31
33
  "keywords": [
32
34
  "Vaadin",
@@ -38,21 +40,21 @@
38
40
  "dependencies": {
39
41
  "@open-wc/dedupe-mixin": "^1.3.0",
40
42
  "@polymer/polymer": "^3.0.0",
41
- "@vaadin/a11y-base": "24.4.0-dev.4b20a0c55.3",
42
- "@vaadin/component-base": "24.4.0-dev.4b20a0c55.3",
43
- "@vaadin/field-base": "24.4.0-dev.4b20a0c55.3",
44
- "@vaadin/input-container": "24.4.0-dev.4b20a0c55.3",
45
- "@vaadin/item": "24.4.0-dev.4b20a0c55.3",
46
- "@vaadin/lit-renderer": "24.4.0-dev.4b20a0c55.3",
47
- "@vaadin/overlay": "24.4.0-dev.4b20a0c55.3",
48
- "@vaadin/vaadin-lumo-styles": "24.4.0-dev.4b20a0c55.3",
49
- "@vaadin/vaadin-material-styles": "24.4.0-dev.4b20a0c55.3",
50
- "@vaadin/vaadin-themable-mixin": "24.4.0-dev.4b20a0c55.3"
43
+ "@vaadin/a11y-base": "24.4.0-rc1",
44
+ "@vaadin/component-base": "24.4.0-rc1",
45
+ "@vaadin/field-base": "24.4.0-rc1",
46
+ "@vaadin/input-container": "24.4.0-rc1",
47
+ "@vaadin/item": "24.4.0-rc1",
48
+ "@vaadin/lit-renderer": "24.4.0-rc1",
49
+ "@vaadin/overlay": "24.4.0-rc1",
50
+ "@vaadin/vaadin-lumo-styles": "24.4.0-rc1",
51
+ "@vaadin/vaadin-material-styles": "24.4.0-rc1",
52
+ "@vaadin/vaadin-themable-mixin": "24.4.0-rc1"
51
53
  },
52
54
  "devDependencies": {
53
55
  "@esm-bundle/chai": "^4.3.4",
54
56
  "@vaadin/testing-helpers": "^0.6.0",
55
- "@vaadin/text-field": "24.4.0-dev.4b20a0c55.3",
57
+ "@vaadin/text-field": "24.4.0-rc1",
56
58
  "lit": "^3.0.0",
57
59
  "sinon": "^13.0.2"
58
60
  },
@@ -60,5 +62,5 @@
60
62
  "web-types.json",
61
63
  "web-types.lit.json"
62
64
  ],
63
- "gitHead": "41cf17453d7506fb635c088a0425e20b6e82b89b"
65
+ "gitHead": "a81e3b927d44c56613fa4e1307494a2acc81005f"
64
66
  }
@@ -3,8 +3,6 @@
3
3
  * Copyright (c) 2015 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { DataProviderController } from '@vaadin/component-base/src/data-provider-controller/data-provider-controller.js';
7
- import { get } from '@vaadin/component-base/src/path-utils.js';
8
6
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
9
7
 
10
8
  /**
@@ -23,6 +21,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
23
21
  type: Number,
24
22
  value: 50,
25
23
  observer: '_pageSizeChanged',
24
+ sync: true,
26
25
  },
27
26
 
28
27
  /**
@@ -32,6 +31,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
32
31
  size: {
33
32
  type: Number,
34
33
  observer: '_sizeChanged',
34
+ sync: true,
35
35
  },
36
36
 
37
37
  /**
@@ -51,6 +51,14 @@ export const ComboBoxDataProviderMixin = (superClass) =>
51
51
  dataProvider: {
52
52
  type: Object,
53
53
  observer: '_dataProviderChanged',
54
+ sync: true,
55
+ },
56
+
57
+ /** @private */
58
+ _pendingRequests: {
59
+ value: () => {
60
+ return {};
61
+ },
54
62
  },
55
63
 
56
64
  /** @private */
@@ -62,12 +70,6 @@ export const ComboBoxDataProviderMixin = (superClass) =>
62
70
  __previousDataProviderFilter: {
63
71
  type: String,
64
72
  },
65
-
66
- /** @private */
67
- _hasData: {
68
- type: Boolean,
69
- value: false,
70
- },
71
73
  };
72
74
  }
73
75
 
@@ -79,46 +81,20 @@ export const ComboBoxDataProviderMixin = (superClass) =>
79
81
  ];
80
82
  }
81
83
 
82
- constructor() {
83
- super();
84
-
85
- /** @type {DataProviderController} */
86
- this._dataProviderController = new DataProviderController(this, {
87
- size: this.size,
88
- pageSize: this.pageSize,
89
- getItemId: (item) => get(this.itemIdPath, item),
90
- placeholder: this.__placeHolder,
91
- dataProvider: this.dataProvider ? this.dataProvider.bind(this) : null,
92
- dataProviderParams: () => ({ filter: this.filter }),
93
- });
94
- }
95
-
96
84
  /** @protected */
97
85
  ready() {
98
86
  super.ready();
99
-
100
- this._dataProviderController.addEventListener('page-requested', this.__onDataProviderPageRequested.bind(this));
101
- this._dataProviderController.addEventListener('page-loaded', this.__onDataProviderPageLoaded.bind(this));
102
-
103
87
  this._scroller.addEventListener('index-requested', (e) => {
104
88
  if (!this._shouldFetchData()) {
105
89
  return;
106
90
  }
107
91
 
108
92
  const index = e.detail.index;
109
- const currentScrollerPos = e.detail.currentScrollerPos;
110
- const allowedIndexRange = Math.floor(this.pageSize * 1.5);
111
-
112
- // Ignores the indexes, which are being re-sent during scrolling reset,
113
- // if the corresponding page is around the current scroller position.
114
- // Otherwise, there might be a last pages duplicates, which cause the
115
- // loading indicator hanging and blank items
116
- if (this._shouldSkipIndex(index, allowedIndexRange, currentScrollerPos)) {
117
- return;
118
- }
119
-
120
93
  if (index !== undefined) {
121
- this._dataProviderController.ensureFlatIndexLoaded(index);
94
+ const page = this._getPageForIndex(index);
95
+ if (this._shouldLoadPage(page)) {
96
+ this._loadPage(page);
97
+ }
122
98
  }
123
99
  });
124
100
  }
@@ -133,10 +109,11 @@ export const ComboBoxDataProviderMixin = (superClass) =>
133
109
  if (this.__previousDataProviderFilter !== filter) {
134
110
  this.__previousDataProviderFilter = filter;
135
111
 
136
- this._keepOverlayOpened = true;
112
+ this.__keepOverlayOpened = true;
113
+ this._pendingRequests = {};
137
114
  this.size = undefined;
138
115
  this.clearCache();
139
- this._keepOverlayOpened = false;
116
+ this.__keepOverlayOpened = false;
140
117
  }
141
118
  }
142
119
 
@@ -155,114 +132,110 @@ export const ComboBoxDataProviderMixin = (superClass) =>
155
132
  return;
156
133
  }
157
134
 
158
- if (opened && !this._hasData) {
159
- this._dataProviderController.loadFirstPage();
135
+ if (opened && this._shouldLoadPage(0)) {
136
+ this._loadPage(0);
160
137
  }
161
138
  }
162
139
 
163
140
  /** @private */
164
- _shouldSkipIndex(index, allowedIndexRange, currentScrollerPos) {
165
- return (
166
- currentScrollerPos !== 0 &&
167
- index >= currentScrollerPos - allowedIndexRange &&
168
- index <= currentScrollerPos + allowedIndexRange
169
- );
170
- }
141
+ _shouldLoadPage(page) {
142
+ if (this._forceNextRequest) {
143
+ this._forceNextRequest = false;
144
+ return true;
145
+ }
171
146
 
172
- /** @private */
173
- __onDataProviderPageRequested() {
174
- this.loading = true;
147
+ const loadedItem = this.filteredItems[page * this.pageSize];
148
+ if (loadedItem !== undefined) {
149
+ return loadedItem instanceof ComboBoxPlaceholder;
150
+ }
151
+ return this.size === undefined;
175
152
  }
176
153
 
177
154
  /** @private */
178
- __onDataProviderPageLoaded() {
179
- this._hasData = true;
155
+ _loadPage(page) {
156
+ // Make sure same page isn't requested multiple times.
157
+ if (this._pendingRequests[page] || !this.dataProvider) {
158
+ return;
159
+ }
180
160
 
181
- this.requestContentUpdate();
161
+ const params = {
162
+ page,
163
+ pageSize: this.pageSize,
164
+ filter: this.filter,
165
+ };
182
166
 
183
- if (!this.opened && !this._isInputFocused()) {
184
- this._commitValue();
185
- }
186
- }
167
+ const callback = (items, size) => {
168
+ if (this._pendingRequests[page] !== callback) {
169
+ return;
170
+ }
187
171
 
188
- /**
189
- * Clears the cached pages and reloads data from dataprovider when needed.
190
- */
191
- clearCache() {
192
- if (!this.dataProvider) {
193
- return;
194
- }
172
+ const filteredItems = this.filteredItems ? [...this.filteredItems] : [];
173
+ filteredItems.splice(params.page * params.pageSize, items.length, ...items);
174
+ this.filteredItems = filteredItems;
195
175
 
196
- this._dataProviderController.clearCache();
176
+ if (!this.opened && !this._isInputFocused()) {
177
+ this._commitValue();
178
+ }
197
179
 
198
- this._hasData = false;
180
+ if (size !== undefined) {
181
+ this.size = size;
182
+ }
199
183
 
200
- this.requestContentUpdate();
184
+ delete this._pendingRequests[page];
201
185
 
202
- if (this._shouldFetchData()) {
203
- this._dataProviderController.loadFirstPage();
204
- }
186
+ if (Object.keys(this._pendingRequests).length === 0) {
187
+ this.loading = false;
188
+ }
189
+ };
190
+
191
+ this._pendingRequests[page] = callback;
192
+ // Set the `loading` flag only after marking the request as pending
193
+ // to prevent the same page from getting requested multiple times
194
+ // as a result of `__loadingChanged` in the scroller which requests
195
+ // a virtualizer update which in turn may trigger a data provider page request.
196
+ this.loading = true;
197
+ this.dataProvider(params, callback);
205
198
  }
206
199
 
207
200
  /** @private */
208
- _sizeChanged(size = 0) {
209
- const { rootCache } = this._dataProviderController;
210
- // When the size update originates from the developer,
211
- // sync the new size with the controller and trigger
212
- // a content update to re-render the scroller.
213
- if (rootCache.size !== size) {
214
- rootCache.size = size;
215
- this.requestContentUpdate();
216
- }
201
+ _getPageForIndex(index) {
202
+ return Math.floor(index / this.pageSize);
217
203
  }
218
204
 
219
205
  /**
220
- * @private
221
- * @override
206
+ * Clears the cached pages and reloads data from dataprovider when needed.
222
207
  */
223
- _filteredItemsChanged(items) {
208
+ clearCache() {
224
209
  if (!this.dataProvider) {
225
- return super._filteredItemsChanged(items);
210
+ return;
226
211
  }
227
212
 
228
- const { rootCache } = this._dataProviderController;
229
- // When the items update originates from the developer,
230
- // sync the new items with the controller and trigger
231
- // a content update to re-render the scroller.
232
- if (rootCache.items !== items) {
233
- rootCache.items = items;
234
- this.requestContentUpdate();
213
+ this._pendingRequests = {};
214
+ const filteredItems = [];
215
+ for (let i = 0; i < (this.size || 0); i++) {
216
+ filteredItems.push(this.__placeHolder);
235
217
  }
236
- }
218
+ this.filteredItems = filteredItems;
237
219
 
238
- /** @override */
239
- requestContentUpdate() {
240
- if (this.dataProvider) {
241
- const { rootCache } = this._dataProviderController;
242
-
243
- // Sync the controller's size with the component.
244
- // They can be out of sync after, for example,
245
- // the controller received new data.
246
- if ((this.size || 0) !== rootCache.size) {
247
- this.size = rootCache.size;
248
- }
249
-
250
- // Sync the controller's items with the component.
251
- // They can be out of sync after, for example,
252
- // the controller received new data.
253
- if (this.filteredItems !== rootCache.items) {
254
- this.filteredItems = rootCache.items;
255
- }
256
-
257
- // Sync the controller's loading state with the component.
258
- this.loading = this._dataProviderController.isLoading();
220
+ if (this._shouldFetchData()) {
221
+ this._forceNextRequest = false;
222
+ this._loadPage(0);
223
+ } else {
224
+ this._forceNextRequest = true;
225
+ }
226
+ }
259
227
 
260
- // Set a copy of the controller's items as the dropdown items
261
- // to trigger an update of the focused index in _setDropdownItems.
262
- this._setDropdownItems([...this.filteredItems]);
228
+ /** @private */
229
+ _sizeChanged(size = 0) {
230
+ const filteredItems = (this.filteredItems || []).slice(0, size);
231
+ for (let i = 0; i < size; i++) {
232
+ filteredItems[i] = filteredItems[i] !== undefined ? filteredItems[i] : this.__placeHolder;
263
233
  }
234
+ this.filteredItems = filteredItems;
264
235
 
265
- super.requestContentUpdate();
236
+ // Cleans up the redundant pending requests for pages > size
237
+ // Refers to https://github.com/vaadin/vaadin-flow-components/issues/229
238
+ this._flushPendingRequests(size);
266
239
  }
267
240
 
268
241
  /** @private */
@@ -271,8 +244,6 @@ export const ComboBoxDataProviderMixin = (superClass) =>
271
244
  this.pageSize = oldPageSize;
272
245
  throw new Error('`pageSize` value must be an integer > 0');
273
246
  }
274
-
275
- this._dataProviderController.setPageSize(pageSize);
276
247
  this.clearCache();
277
248
  }
278
249
 
@@ -282,7 +253,6 @@ export const ComboBoxDataProviderMixin = (superClass) =>
282
253
  this.dataProvider = oldDataProvider;
283
254
  });
284
255
 
285
- this._dataProviderController.setDataProvider(dataProvider);
286
256
  this.clearCache();
287
257
  }
288
258
 
@@ -291,6 +261,8 @@ export const ComboBoxDataProviderMixin = (superClass) =>
291
261
  if (this.items !== undefined && this.dataProvider !== undefined) {
292
262
  restoreOldValueCallback();
293
263
  throw new Error('Using `items` and `dataProvider` together is not supported');
264
+ } else if (this.dataProvider && !this.filteredItems) {
265
+ this.filteredItems = [];
294
266
  }
295
267
  }
296
268
 
@@ -309,4 +281,28 @@ export const ComboBoxDataProviderMixin = (superClass) =>
309
281
  }
310
282
  }
311
283
  }
284
+
285
+ /**
286
+ * This method cleans up the page callbacks which refers to the
287
+ * non-existing pages, i.e. which item indexes are greater than the
288
+ * changed size.
289
+ * This case is basically happens when:
290
+ * 1. Users scroll fast to the bottom and combo box generates the
291
+ * redundant page request/callback
292
+ * 2. Server side uses undefined size lazy loading and suddenly reaches
293
+ * the exact size which is on the range edge
294
+ * (for default page size = 50, it will be 100, 200, 300, ...).
295
+ * @param size the new size of items
296
+ * @private
297
+ */
298
+ _flushPendingRequests(size) {
299
+ if (this._pendingRequests) {
300
+ const lastPage = Math.ceil(size / this.pageSize);
301
+ Object.entries(this._pendingRequests).forEach(([page, callback]) => {
302
+ if (parseInt(page) >= lastPage) {
303
+ callback([], size);
304
+ }
305
+ });
306
+ }
307
+ }
312
308
  };
@@ -60,7 +60,7 @@ export const ComboBoxItemMixin = (superClass) =>
60
60
  }
61
61
 
62
62
  static get observers() {
63
- return ['__rendererOrItemChanged(renderer, index, item.*, selected, focused)', '__updateLabel(label, renderer)'];
63
+ return ['__rendererOrItemChanged(renderer, index, item, selected, focused)', '__updateLabel(label, renderer)'];
64
64
  }
65
65
 
66
66
  static get observedAttributes() {
@@ -71,6 +71,7 @@ export const ComboBoxMixin = (subclass) =>
71
71
  notify: true,
72
72
  value: false,
73
73
  reflectToAttribute: true,
74
+ sync: true,
74
75
  observer: '_openedChanged',
75
76
  },
76
77
 
@@ -80,6 +81,7 @@ export const ComboBoxMixin = (subclass) =>
80
81
  */
81
82
  autoOpenDisabled: {
82
83
  type: Boolean,
84
+ sync: true,
83
85
  },
84
86
 
85
87
  /**
@@ -104,7 +106,10 @@ export const ComboBoxMixin = (subclass) =>
104
106
  * - `model.item` The item.
105
107
  * @type {ComboBoxRenderer | undefined}
106
108
  */
107
- renderer: Function,
109
+ renderer: {
110
+ type: Object,
111
+ sync: true,
112
+ },
108
113
 
109
114
  /**
110
115
  * A full set of items to filter the visible options from.
@@ -113,6 +118,7 @@ export const ComboBoxMixin = (subclass) =>
113
118
  */
114
119
  items: {
115
120
  type: Array,
121
+ sync: true,
116
122
  observer: '_itemsChanged',
117
123
  },
118
124
 
@@ -138,6 +144,7 @@ export const ComboBoxMixin = (subclass) =>
138
144
  filteredItems: {
139
145
  type: Array,
140
146
  observer: '_filteredItemsChanged',
147
+ sync: true,
141
148
  },
142
149
 
143
150
  /**
@@ -154,6 +161,7 @@ export const ComboBoxMixin = (subclass) =>
154
161
  type: Boolean,
155
162
  value: false,
156
163
  reflectToAttribute: true,
164
+ sync: true,
157
165
  },
158
166
 
159
167
  /**
@@ -164,6 +172,7 @@ export const ComboBoxMixin = (subclass) =>
164
172
  type: Number,
165
173
  observer: '_focusedIndexChanged',
166
174
  value: -1,
175
+ sync: true,
167
176
  },
168
177
 
169
178
  /**
@@ -174,6 +183,7 @@ export const ComboBoxMixin = (subclass) =>
174
183
  type: String,
175
184
  value: '',
176
185
  notify: true,
186
+ sync: true,
177
187
  },
178
188
 
179
189
  /**
@@ -183,6 +193,7 @@ export const ComboBoxMixin = (subclass) =>
183
193
  selectedItem: {
184
194
  type: Object,
185
195
  notify: true,
196
+ sync: true,
186
197
  },
187
198
 
188
199
  /**
@@ -199,6 +210,7 @@ export const ComboBoxMixin = (subclass) =>
199
210
  type: String,
200
211
  value: 'label',
201
212
  observer: '_itemLabelPathChanged',
213
+ sync: true,
202
214
  },
203
215
 
204
216
  /**
@@ -214,6 +226,7 @@ export const ComboBoxMixin = (subclass) =>
214
226
  itemValuePath: {
215
227
  type: String,
216
228
  value: 'value',
229
+ sync: true,
217
230
  },
218
231
 
219
232
  /**
@@ -223,7 +236,10 @@ export const ComboBoxMixin = (subclass) =>
223
236
  * `dataProvider` callback).
224
237
  * @attr {string} item-id-path
225
238
  */
226
- itemIdPath: String,
239
+ itemIdPath: {
240
+ type: String,
241
+ sync: true,
242
+ },
227
243
 
228
244
  /**
229
245
  * @type {!HTMLElement | undefined}
@@ -240,27 +256,38 @@ export const ComboBoxMixin = (subclass) =>
240
256
  */
241
257
  _dropdownItems: {
242
258
  type: Array,
259
+ sync: true,
243
260
  },
244
261
 
245
262
  /** @private */
246
263
  _closeOnBlurIsPrevented: Boolean,
247
264
 
248
265
  /** @private */
249
- _scroller: Object,
266
+ _scroller: {
267
+ type: Object,
268
+ sync: true,
269
+ },
250
270
 
251
271
  /** @private */
252
272
  _overlayOpened: {
253
273
  type: Boolean,
274
+ sync: true,
254
275
  observer: '_overlayOpenedChanged',
255
276
  },
277
+
278
+ /** @private */
279
+ __keepOverlayOpened: {
280
+ type: Boolean,
281
+ sync: true,
282
+ },
256
283
  };
257
284
  }
258
285
 
259
286
  static get observers() {
260
287
  return [
261
288
  '_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
262
- '_openedOrItemsChanged(opened, _dropdownItems, loading, _keepOverlayOpened)',
263
- '_updateScroller(_scroller, _dropdownItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
289
+ '_openedOrItemsChanged(opened, _dropdownItems, loading, __keepOverlayOpened)',
290
+ '_updateScroller(_scroller, _dropdownItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, _theme)',
264
291
  ];
265
292
  }
266
293
 
@@ -413,6 +440,18 @@ export const ComboBoxMixin = (subclass) =>
413
440
  }
414
441
  }
415
442
 
443
+ /**
444
+ * Override LitElement lifecycle callback to handle filter property change.
445
+ * @param {Object} props
446
+ */
447
+ updated(props) {
448
+ super.updated(props);
449
+
450
+ if (props.has('filter')) {
451
+ this._filterChanged(this.filter);
452
+ }
453
+ }
454
+
416
455
  /** @private */
417
456
  _initOverlay() {
418
457
  const overlay = this.$.overlay;
@@ -441,25 +480,23 @@ export const ComboBoxMixin = (subclass) =>
441
480
  * @protected
442
481
  */
443
482
  _initScroller(host) {
444
- const scrollerTag = `${this._tagNamePrefix}-scroller`;
483
+ const scroller = document.createElement(`${this._tagNamePrefix}-scroller`);
484
+
485
+ scroller.owner = host || this;
486
+ scroller.getItemLabel = this._getItemLabel.bind(this);
487
+ scroller.addEventListener('selection-changed', this._boundOverlaySelectedItemChanged);
445
488
 
446
489
  const overlay = this._overlayElement;
447
490
 
448
491
  overlay.renderer = (root) => {
449
- if (!root.firstChild) {
450
- root.appendChild(document.createElement(scrollerTag));
492
+ if (!root.innerHTML) {
493
+ root.appendChild(scroller);
451
494
  }
452
495
  };
453
496
 
454
497
  // Ensure the scroller is rendered
455
498
  overlay.requestContentUpdate();
456
499
 
457
- const scroller = overlay.querySelector(scrollerTag);
458
-
459
- scroller.owner = host || this;
460
- scroller.getItemLabel = this._getItemLabel.bind(this);
461
- scroller.addEventListener('selection-changed', this._boundOverlaySelectedItemChanged);
462
-
463
500
  // Trigger the observer to set properties
464
501
  this._scroller = scroller;
465
502
  }
@@ -483,6 +520,17 @@ export const ComboBoxMixin = (subclass) =>
483
520
  renderer,
484
521
  theme,
485
522
  });
523
+
524
+ // NOTE: in PolylitMixin, setProperties() waits for `hasUpdated` to be set.
525
+ // This means for the first opening, properties won't be set synchronously.
526
+ // Call `performUpdate()` in this case to mimic the Polymer version logic.
527
+ if (scroller.performUpdate && !scroller.hasUpdated) {
528
+ try {
529
+ scroller.performUpdate();
530
+ } catch (_) {
531
+ // Suppress errors in synchronous tests for pre-opened combo-box.
532
+ }
533
+ }
486
534
  }
487
535
  }
488
536
 
@@ -490,7 +538,7 @@ export const ComboBoxMixin = (subclass) =>
490
538
  _openedOrItemsChanged(opened, items, loading, keepOverlayOpened) {
491
539
  // Close the overlay if there are no items to display.
492
540
  // See https://github.com/vaadin/vaadin-combo-box/pull/964
493
- this._overlayOpened = !!(opened && (keepOverlayOpened || loading || (items && items.length)));
541
+ this._overlayOpened = opened && (keepOverlayOpened || loading || !!(items && items.length));
494
542
  }
495
543
 
496
544
  /** @private */
@@ -1126,10 +1174,6 @@ export const ComboBoxMixin = (subclass) =>
1126
1174
  this.items = oldItems;
1127
1175
  });
1128
1176
 
1129
- if (this.dataProvider) {
1130
- return;
1131
- }
1132
-
1133
1177
  if (items) {
1134
1178
  this.filteredItems = items.slice(0);
1135
1179
  } else if (oldItems) {