From 3ddbe147eceeb606aa805acefa3e29cd6c5a2e6d Mon Sep 17 00:00:00 2001 From: AlexanderMoiseev Date: Wed, 27 Sep 2023 12:19:54 +0400 Subject: [PATCH] DropDownBox: items in the value should be sorted by selection order on async load (T1181665) (#25642) --- packages/devextreme/js/ui/drop_down_box.js | 17 ++++-- .../dropDownBox.tests.js | 58 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/devextreme/js/ui/drop_down_box.js b/packages/devextreme/js/ui/drop_down_box.js index 200c778323e0..245481429a8d 100644 --- a/packages/devextreme/js/ui/drop_down_box.js +++ b/packages/devextreme/js/ui/drop_down_box.js @@ -136,6 +136,14 @@ const DropDownBox = DropDownEditor.inherit({ }); }, + _sortValuesByKeysOrder(orderedKeys, values) { + const sortedValues = values.sort((a, b) => { + return orderedKeys.indexOf(a.itemKey) - orderedKeys.indexOf(b.itemKey); + }); + + return sortedValues.map(x => x.itemDisplayValue); + }, + _renderInputValue: function() { this._rejectValueLoading(); const values = []; @@ -157,9 +165,9 @@ const DropDownBox = DropDownEditor.inherit({ .always(item => { const displayValue = this._displayGetter(item); if(isDefined(displayValue)) { - values.push(displayValue); + values.push({ itemKey: key, itemDisplayValue: displayValue }); } else if(this.option('acceptCustomValue')) { - values.push(key); + values.push({ itemKey: key, itemDisplayValue: key }); } deferred.resolve(); }); @@ -170,8 +178,9 @@ const DropDownBox = DropDownEditor.inherit({ return when .apply(this, itemLoadDeferreds) .always(() => { - this.option('displayValue', values); - callBase(values.length && values); + const orderedValues = this._sortValuesByKeysOrder(keys, values); + this.option('displayValue', orderedValues); + callBase(values.length && orderedValues); }); }, diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/dropDownBox.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/dropDownBox.tests.js index 6f02863b12ce..2d6d306f469f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/dropDownBox.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/dropDownBox.tests.js @@ -50,6 +50,64 @@ const moduleConfig = { } }; +QUnit.module('items order', moduleConfig, () => { + function getStore(items) { + return { + load: () => { + $.Deferred().resolve(items).promise(); + }, + byKey: (key) => { + const d = $.Deferred(); + if(key === 10250) { + setTimeout(() => { + d.resolve(items[0]); + }, 300); + } else if(key === 10252) { + setTimeout(() => { + d.resolve(items[1]); + }, 500); + } else { + d.resolve(items[2]); + } + + return d.promise(); + } + }; + } + + QUnit.test('should be correct when items loaded asynchronously and display value is set', function(assert) { + const items = [{ id: 10250, name: 'HANAR' }, { id: 10252, name: 'SUPRD' }, { id: 10249, name: 'Tomps' }]; + + const instance = this.$element.dxDropDownBox({ + dataSource: getStore(items), + valueExpr: 'id', + displayExpr: 'name', + value: [10250, 10252, 10249] + }).dxDropDownBox('instance'); + + this.clock.tick(500); + + assert.deepEqual(instance.option('value'), [10250, 10252, 10249], 'value is correct'); + assert.strictEqual(instance.option('text'), 'HANAR, SUPRD, Tomps', 'text is correct'); + assert.strictEqual($(`.${TEXTEDITOR_INPUT_CLASS}`).val(), 'HANAR, SUPRD, Tomps', 'input value is correct'); + }); + + QUnit.test('should be correct when items loaded asynchronously (T1181665)', function(assert) { + const items = [10250, 10252, 10249]; + + const instance = this.$element.dxDropDownBox({ + dataSource: getStore(items), + value: items + }).dxDropDownBox('instance'); + + this.clock.tick(500); + + assert.deepEqual(instance.option('value'), [10250, 10252, 10249], 'value is correct'); + assert.strictEqual(instance.option('text'), '10250, 10252, 10249', 'text is correct'); + assert.strictEqual($(`.${TEXTEDITOR_INPUT_CLASS}`).val(), '10250, 10252, 10249', 'input value is correct'); + }); +}); + QUnit.module('common', moduleConfig, () => { QUnit.test('the widget should display custom value without the dataSource', function(assert) { this.$element.dxDropDownBox({ value: 1, acceptCustomValue: true });