From deff69bd87f1a5f4a2315b1867b986b80525083d Mon Sep 17 00:00:00 2001 From: Damyan Petev Date: Tue, 7 Nov 2023 20:41:02 +0200 Subject: [PATCH] fix(simple-combo): value & selection correct single type instead array --- CHANGELOG.md | 2 + .../src/lib/combo/combo.common.ts | 2 +- .../src/lib/simple-combo/README.md | 5 +- .../simple-combo/simple-combo.component.html | 2 +- .../simple-combo.component.spec.ts | 272 +++++++++--------- .../simple-combo/simple-combo.component.ts | 51 ++-- 6 files changed, 174 insertions(+), 160 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa50b15860..7b7814d7e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ All notable changes for each version of this project will be documented in this - `ISimpleComboSelectionChangingEventArgs` exposes two new properties `newSelection` and `oldSelection` in place of the old ones that are no longer affected by `valueKey` and consistently emit items from Combo's `data`. Note: In remote data scenarios with `valueKey` set, selected items that are not currently part of the loaded data chunk will be emitted a partial item data object with the `valueKey` property. + - **Breaking Change** The `value` and `selection` properties now correctly return a single value or data item instead of the same wrapped in array and `undefined` instead of empty array, matching the values emitted from selection event and when working with `formControlName`/`ngModel` directives. + ## 16.1.4 ### New Features - `Themes`: diff --git a/projects/igniteui-angular/src/lib/combo/combo.common.ts b/projects/igniteui-angular/src/lib/combo/combo.common.ts index e85d09e8000..241900abc48 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.common.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.common.ts @@ -795,7 +795,7 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement } /** - * The value of the selected item in the combo + * The value of the combo * * ```typescript * // get diff --git a/projects/igniteui-angular/src/lib/simple-combo/README.md b/projects/igniteui-angular/src/lib/simple-combo/README.md index 3853c520262..afa3467434d 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/README.md +++ b/projects/igniteui-angular/src/lib/simple-combo/README.md @@ -272,8 +272,9 @@ Setting `[displayDensity]` affects the control's items' and inputs' css properti | Name | Description | Type | |--------------------------|---------------------------------------------------|-----------------------------| | `id` | The combo's id. | `string` | -| `data` | The combo's data source. | `any` | -| `value` | The combo's value. | `string` | +| `data` | The combo's data source. | `any[]` | +| `value` | The combo's value. | `any` | +| `selection` | The combo's selected item. | `any` | | `allowCustomValue` | Enables/disables combo custom value. | `boolean` | | `valueKey` | Determines which column in the data source is used to determine the value. | `string` | | `displayKey` | Determines which column in the data source is used to determine the display value. | `string` | diff --git a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html index c29cc18f4cf..ed3a5271552 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html +++ b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html @@ -24,7 +24,7 @@ - diff --git a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.spec.ts b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.spec.ts index ba889329b0e..6db697b401f 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.spec.ts +++ b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.spec.ts @@ -145,30 +145,26 @@ describe('IgxSimpleCombo', () => { combo.dropdown = dropdown; spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length); - const selectedItems = [combo.data[0]]; - const selectedValues = [combo.data[0].country]; + let selectedItem = combo.data[0]; + let selectedValue = combo.data[0].country; combo.select('UK'); - expect(combo.selection).toEqual(selectedItems); - expect(combo.value).toEqual(selectedValues); + expect(combo.selection).toEqual(selectedItem); + expect(combo.value).toEqual(selectedValue); combo.select('Germany'); - selectedItems.push(combo.data[2]); - selectedValues.push(combo.data[2].country); - selectedItems.shift(); - selectedValues.shift(); - expect(combo.selection).toEqual(selectedItems); - expect(combo.value).toEqual(selectedValues); - - selectedItems.shift(); + selectedItem = combo.data[2]; + selectedValue = combo.data[2].country; + expect(combo.selection).toEqual(selectedItem); + expect(combo.value).toEqual(selectedValue); + combo.valueKey = null; // without valueKey - selectedItems.push(combo.data[5]); + selectedItem = combo.data[5]; combo.select(combo.data[5]); - expect(combo.selection).toEqual(selectedItems); - expect(combo.value).toEqual(selectedItems); - selectedItems.shift(); - selectedItems.push(combo.data[1]); + expect(combo.selection).toEqual(selectedItem); + expect(combo.value).toEqual(selectedItem); + selectedItem = combo.data[1]; combo.select(combo.data[1]); - expect(combo.selection).toEqual(selectedItems); - expect(combo.value).toEqual(selectedItems); + expect(combo.selection).toEqual(selectedItem); + expect(combo.value).toEqual(selectedItem); }); it('should emit owner on `opening` and `closing`', () => { combo = new IgxSimpleComboComponent(elementRef, mockCdr, mockSelection as any, mockComboService, @@ -300,15 +296,15 @@ describe('IgxSimpleCombo', () => { combo.data = data; combo.dropdown = dropdown; spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length); - spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.newValue = []); + spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.newValue = undefined); const comboInput = jasmine.createSpyObj('IgxInputDirective', ['value']); combo.comboInput = comboInput; // No items are initially selected - expect(combo.selection).toEqual([]); + expect(combo.selection).toEqual(undefined); // Select the first item combo.select(combo.data[0]); - // selectionChanging fires and overrides the selection to be []; - expect(combo.selection).toEqual([]); + // selectionChanging fires and overrides, selection should remain undefined + expect(combo.selection).toEqual(undefined); }); it('should not throw error when setting data to null', () => { combo = new IgxSimpleComboComponent(elementRef, mockCdr, mockSelection as any, mockComboService, @@ -726,8 +722,8 @@ describe('IgxSimpleCombo', () => { component.selectedItem = 1; fixture.detectChanges(); tick(); - expect(combo.selection).toEqual([combo.data[1]]); - expect(combo.value).toEqual([combo.data[1][combo.valueKey]]); + expect(combo.selection).toEqual(combo.data[1]); + expect(combo.value).toEqual(combo.data[1][combo.valueKey]); combo.select(combo.data[4][combo.valueKey]); fixture.detectChanges(); expect(component.selectedItem).toEqual(4); @@ -741,8 +737,8 @@ describe('IgxSimpleCombo', () => { component.selectedItem = component.items[0]; fixture.detectChanges(); tick(); - expect(combo.selection).toEqual([combo.data[0]]); - expect(combo.value).toEqual([combo.data[0]]); + expect(combo.selection).toEqual(combo.data[0]); + expect(combo.value).toEqual(combo.data[0]); combo.select(combo.data[4]); fixture.detectChanges(); expect(component.selectedItem).toEqual(combo.data[4]); @@ -756,8 +752,8 @@ describe('IgxSimpleCombo', () => { component.items = ['One', 'Two', 'Three', 'Four', 'Five']; combo.select('Three'); fixture.detectChanges(); - expect(combo.selection).toEqual(['Three']); - expect(combo.value).toEqual(['Three']); + expect(combo.selection).toEqual('Three'); + expect(combo.value).toEqual('Three'); combo.handleClear(new MouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual([]); @@ -772,8 +768,8 @@ describe('IgxSimpleCombo', () => { component.selectedItem = 'One'; fixture.detectChanges(); tick(); - expect(combo.selection).toEqual([component.selectedItem]); - expect(combo.value).toEqual([component.selectedItem]); + expect(combo.selection).toEqual(component.selectedItem); + expect(combo.value).toEqual(component.selectedItem); combo.select('Three'); fixture.detectChanges(); expect(fixture.componentInstance.selectedItem).toEqual('Three'); @@ -791,13 +787,13 @@ describe('IgxSimpleCombo', () => { combo.select(combo.data[1][combo.valueKey]); expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); - expect(combo.selection).toEqual([selectedItem]); - expect(combo.value).toEqual([selectedItem[combo.valueKey]]); + expect(combo.selection).toEqual(selectedItem); + expect(combo.value).toEqual(selectedItem[combo.valueKey]); // Clear items while they are in view combo.handleClear(spyObj); - expect(combo.selection).toEqual([]); + expect(combo.selection).toEqual(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.value).toEqual(undefined); selectedItem = combo.data[2]; combo.select(combo.data[2][combo.valueKey]); expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); @@ -807,9 +803,9 @@ describe('IgxSimpleCombo', () => { await wait(); fixture.detectChanges(); combo.handleClear(spyObj); - expect(combo.selection).toEqual([]); + expect(combo.selection).toEqual(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.value).toEqual(undefined); combo.select(combo.data[7][combo.valueKey]); expect(combo.displayValue).toEqual([combo.data[7][combo.displayKey]]); })); @@ -897,14 +893,14 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Space', dropdownContent); fixture.detectChanges(); expect(combo.closed.emit).not.toHaveBeenCalled(); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() }); it('should clear the selection on tab/blur if the search text does not match any value', () => { // allowCustomValues does not matter combo.select(combo.data[2][combo.valueKey]); fixture.detectChanges(); - expect(combo.selection.length).toBe(1); + expect(combo.selection).toBeDefined() expect(input.nativeElement.value).toEqual('Massachusetts'); UIInteractions.simulateTyping('L', input, 13, 14); @@ -920,7 +916,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); expect(input.nativeElement.value.length).toEqual(0); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() }); it('should not clear selection on tab/blur after filtering and selecting a value', () => { @@ -929,12 +925,12 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('Enter', input.nativeElement); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() expect(combo.displayValue).toEqual(['Wisconsin']); UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() expect(combo.displayValue).toEqual(['Wisconsin']); }); @@ -1004,7 +1000,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.selection.length).toBe(1); + expect(combo.selection).toBeDefined() }); it('should scroll to top when opened and there is no selection', () => { @@ -1074,7 +1070,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Backspace', input); fixture.detectChanges(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() input.triggerEventHandler('blur', {}); fixture.detectChanges(); @@ -1087,19 +1083,19 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Backspace', input); fixture.detectChanges(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() }); it('should display all list items when clearing the input by Space', () => { combo.select('Wisconsin'); fixture.detectChanges(); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() UIInteractions.simulateTyping(' ', input, 0, 9); fixture.detectChanges(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() expect(combo.filteredData.length).toEqual(combo.data.length); }); @@ -1141,9 +1137,8 @@ describe('IgxSimpleCombo', () => { combo.select(combo.data[1]); fixture.detectChanges(); - expect(combo.selection.length).toBe(1); - expect(combo.selection[0]).toEqual('Apple'); - expect(combo.value[0]).toEqual('Apple'); + expect(combo.selection).toEqual('Apple'); + expect(combo.value).toEqual('Apple'); combo.open(); fixture.detectChanges(); @@ -1152,7 +1147,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual(['Apple']); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() }); it('should clear input on blur when dropdown is collapsed with no match', () => { @@ -1169,7 +1164,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() }); it('should open the combo when input is focused', () => { @@ -1270,8 +1265,8 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual(['0']); - expect(combo.value).toEqual([ 0 ]); - expect(combo.selection).toEqual([{ field: '0', value: 0 }]); + expect(combo.value).toEqual(0); + expect(combo.selection).toEqual({ field: '0', value: 0 }); combo.open(); fixture.detectChanges(); @@ -1281,8 +1276,8 @@ describe('IgxSimpleCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual(['false']); - expect(combo.value).toEqual([ false ]); - expect(combo.selection).toEqual([{ field: 'false', value: false }]); + expect(combo.value).toEqual(false); + expect(combo.selection).toEqual({ field: 'false', value: false }); combo.open(); fixture.detectChanges(); @@ -1292,8 +1287,8 @@ describe('IgxSimpleCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.value).toEqual([ '' ]); - expect(combo.selection).toEqual([{ field: '', value: '' }]); + expect(combo.value).toEqual(''); + expect(combo.selection).toEqual({ field: '', value: '' }); combo.open(); fixture.detectChanges(); @@ -1303,8 +1298,8 @@ describe('IgxSimpleCombo', () => { item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual(['null']); - expect(combo.value).toEqual([ null ]); - expect(combo.selection).toEqual([{ field: 'null', value: null }]); + expect(combo.value).toEqual(null); + expect(combo.selection).toEqual({ field: 'null', value: null }); combo.open(); fixture.detectChanges(); @@ -1314,8 +1309,8 @@ describe('IgxSimpleCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual(['NaN']); - expect(combo.value).toEqual([ NaN ]); - expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); + expect(combo.value).toEqual(NaN); + expect(combo.selection).toEqual({ field: 'NaN', value: NaN }); // should not select "undefined" // combo.displayValue & combo.selection equal the values from the previous selection @@ -1327,8 +1322,8 @@ describe('IgxSimpleCombo', () => { item6.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.displayValue).toEqual(['NaN']); - expect(combo.value).toEqual([ NaN ]); - expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); + expect(combo.value).toEqual(NaN); + expect(combo.selection).toEqual({ field: 'NaN', value: NaN }); }); it('should select falsy values except "undefined" with "writeValue" method', () => { @@ -1344,34 +1339,34 @@ describe('IgxSimpleCombo', () => { ]; combo.writeValue(0); - expect(combo.value).toEqual([0]); - expect(combo.selection).toEqual([{ field: '0', value: 0 }]); + expect(combo.value).toEqual(0); + expect(combo.selection).toEqual({ field: '0', value: 0 }); expect(combo.displayValue).toEqual(['0']); combo.writeValue(false); - expect(combo.value).toEqual([false]); - expect(combo.selection).toEqual([{ field: 'false', value: false }]); + expect(combo.value).toEqual(false); + expect(combo.selection).toEqual({ field: 'false', value: false }); expect(combo.displayValue).toEqual(['false']); combo.writeValue(''); - expect(combo.value).toEqual(['']); - expect(combo.selection).toEqual([{ field: 'empty', value: '' }]); + expect(combo.value).toEqual(''); + expect(combo.selection).toEqual({ field: 'empty', value: '' }); expect(combo.displayValue).toEqual(['empty']); combo.writeValue(null); - expect(combo.value).toEqual([null]); - expect(combo.selection).toEqual([{ field: 'null', value: null }]); + expect(combo.value).toEqual(null); + expect(combo.selection).toEqual({ field: 'null', value: null }); expect(combo.displayValue).toEqual(['null']); combo.writeValue(NaN); - expect(combo.value).toEqual([NaN]); - expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); + expect(combo.value).toEqual(NaN); + expect(combo.selection).toEqual({ field: 'NaN', value: NaN }); expect(combo.displayValue).toEqual(['NaN']); // should not select undefined combo.writeValue(undefined); - expect(combo.value).toEqual([]); - expect(combo.selection).toEqual([]); + expect(combo.value).toEqual(undefined); + expect(combo.selection).toEqual(undefined); expect(combo.displayValue).toEqual([]); }); @@ -1403,7 +1398,7 @@ describe('IgxSimpleCombo', () => { combo.select('Wisconsin'); fixture.detectChanges(); - expect(combo.selection.length).toEqual(1); + expect(combo.selection).toBeDefined() let clearButton = fixture.debugElement.query(By.css(`.${CSS_CLASS_CLEARBUTTON}`)); expect(clearButton).not.toBeNull(); @@ -1413,7 +1408,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.simulateTyping('L', input, 9, 10); fixture.detectChanges(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() //should hide the clear button immediately when clearing the selection by typing clearButton = fixture.debugElement.query(By.css(`.${CSS_CLASS_CLEARBUTTON}`)); @@ -1440,8 +1435,7 @@ describe('IgxSimpleCombo', () => { combo.select('Connecticut'); fixture.detectChanges(); - expect(combo.selection.length).toBe(1); - expect(combo.selection[0]).toEqual({ field: 'Connecticut', region: 'New England' }); + expect(combo.selection).toEqual({ field: 'Connecticut', region: 'New England' }); fixture.detectChanges(); combo.dropdown.close(); @@ -1634,8 +1628,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1647,8 +1641,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1660,8 +1654,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1684,8 +1678,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1697,8 +1691,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1724,22 +1718,22 @@ describe('IgxSimpleCombo', () => { combo.writeValue(null); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1759,22 +1753,22 @@ describe('IgxSimpleCombo', () => { combo.writeValue(null); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1812,8 +1806,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); expect(reactiveForm.status).toEqual('INVALID'); @@ -1827,8 +1821,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1842,8 +1836,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1857,8 +1851,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1872,8 +1866,8 @@ describe('IgxSimpleCombo', () => { reactiveForm.resetForm(); fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); expect(reactiveForm.status).toEqual('INVALID'); @@ -1887,8 +1881,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1902,8 +1896,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1924,8 +1918,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); expect(reactiveForm.status).toEqual('INVALID'); @@ -1936,8 +1930,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(null); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1945,8 +1939,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(''); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1954,8 +1948,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1970,8 +1964,8 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); expect(reactiveForm.status).toEqual('INVALID'); @@ -1982,8 +1976,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(null); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -1991,8 +1985,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(''); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -2000,8 +1994,8 @@ describe('IgxSimpleCombo', () => { combo.writeValue(undefined); expect(combo.displayValue).toEqual([]); - expect(combo.selection).toEqual([]); - expect(combo.value).toEqual([]); + expect(combo.selection).toEqual(undefined); + expect(combo.value).toEqual(undefined); expect(combo.valid).toEqual(IgxInputState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); expect(reactiveForm.status).toEqual('INVALID'); @@ -2064,7 +2058,7 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() expect((combo as any)._remoteSelection[0]).toBeUndefined(); }); it('should add predefined selection to the input when data is bound after initialization', fakeAsync(() => { @@ -2080,7 +2074,7 @@ describe('IgxSimpleCombo', () => { })); it('should clear selection and not clear value when bound to remote data and item is out of view', (async () => { expect(combo.valueKey).toBeDefined(); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() const selectedItem = combo.data[1]; combo.toggle(); @@ -2097,22 +2091,20 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.selection.length).toEqual(1); - expect(combo.value.length).toEqual(1); + expect(combo.selection).toBeDefined() expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); - expect(combo.value).toEqual([selectedItem[combo.valueKey]]); + expect(combo.value).toEqual(selectedItem[combo.valueKey]); })); it('should set combo.displayValue to empty string when bound to remote data and selected item\'s data is not present', (async () => { expect(combo.valueKey).toBeDefined(); expect(combo.valueKey).toEqual('id'); - expect(combo.selection.length).toEqual(0); + expect(combo.selection).not.toBeDefined() // current combo data - id: 0 - 9 // select item that is not present in the data source yet combo.select(15); - expect(combo.selection.length).toEqual(1); - expect(combo.value.length).toEqual(1); + expect(combo.selection).toBeDefined() expect(combo.displayValue).toEqual([]); combo.toggle(); diff --git a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts index 359160f53c0..acc2206ad5b 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts +++ b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts @@ -93,6 +93,22 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co @ViewChild(IgxTextSelectionDirective, { static: true }) private textSelection: IgxTextSelectionDirective; + public override get value(): any { + return this._value[0]; + } + + /** + * Get current selection state + * + * @returns The selected item, if any + * ```typescript + * let mySelection = this.combo.selection; + * ``` + */ + public override get selection(): any { + return super.selection[0]; + } + /** @hidden @internal */ public composing = false; @@ -125,6 +141,10 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co return this.selectionService.get(this.id).values().next().value; } + protected get hasSelectedItem(): boolean { + return !!this.selectionService.get(this.id).size; + } + constructor(elementRef: ElementRef, cdr: ChangeDetectorRef, selectionService: IgxSelectionAPIService, @@ -148,7 +168,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co event.stopPropagation(); this.open(); } else { - if (this.virtDir.igxForOf.length > 0 && !this.selectedItem) { + if (this.virtDir.igxForOf.length > 0 && !this.hasSelectedItem) { this.dropdown.navigateNext(); this.dropdownContainer.nativeElement.focus(); } else if (this.allowCustomValues) { @@ -186,24 +206,24 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co /** @hidden @internal */ public writeValue(value: any): void { - const oldSelection = this.selection; + const oldSelection = super.selection; this.selectionService.select_items(this.id, this.isValid(value) ? [value] : [], true); this.cdr.markForCheck(); - this._displayValue = this.createDisplayText(this.selection, oldSelection); - this._value = this.valueKey ? this.selection.map(item => item[this.valueKey]) : this.selection; + this._displayValue = this.createDisplayText(super.selection, oldSelection); + this._value = this.valueKey ? super.selection.map(item => item[this.valueKey]) : super.selection; this.filterValue = this._internalFilter = this._displayValue?.toString(); } /** @hidden @internal */ public override ngAfterViewInit(): void { this.virtDir.contentSizeChange.pipe(takeUntil(this.destroy$)).subscribe(() => { - if (this.selection.length > 0) { + if (super.selection.length > 0) { const index = this.virtDir.igxForOf.findIndex(e => { let current = e? e[this.valueKey] : undefined; if (this.valueKey === null || this.valueKey === undefined) { current = e; } - return current === this.selection[0]; + return current === super.selection[0]; }); if (!this.isRemote) { // navigate to item only if we have local data @@ -259,9 +279,9 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co /** @hidden @internal */ public override ngDoCheck(): void { - if (this.data?.length && this.selection.length && !this._displayValue) { - this._displayValue = this.createDisplayText(this.selection, []); - this._value = this.valueKey ? this.selection.map(item => item[this.valueKey]) : this.selection; + if (this.data?.length && super.selection.length && !this._displayValue) { + this._displayValue = this.createDisplayText(super.selection, []); + this._value = this.valueKey ? super.selection.map(item => item[this.valueKey]) : super.selection; } super.ngDoCheck(); } @@ -275,13 +295,13 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co if (this.collapsed && this.comboInput.focused) { this.open(); } - if (!this.comboInput.value.trim() && this.selection.length) { + if (!this.comboInput.value.trim() && super.selection.length) { // handle clearing of input by space this.clearSelection(); this._onChangeCallback(null); this.filterValue = ''; } - if (this.selection.length) { + if (super.selection.length) { this.selectionService.clear(this.id); } // when filtering the focused item should be the first item or the currently selected item @@ -332,9 +352,8 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co /** @hidden @internal */ public handleKeyUp(event: KeyboardEvent): void { if (event.key === this.platformUtil.KEYMAP.ARROW_DOWN) { - const firstItem = this.selectionService.first_item(this.id); - this.dropdown.focusedItem = firstItem && this.filteredData.length > 0 - ? this.dropdown.items.find(i => i.itemID === firstItem) + this.dropdown.focusedItem = this.hasSelectedItem && this.filteredData.length > 0 + ? this.dropdown.items.find(i => i.itemID === this.selectedItem) : this.dropdown.items[0]; this.dropdownContainer.nativeElement.focus(); } @@ -475,7 +494,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co if (this._updateInput) { this.comboInput.value = this._internalFilter = this._displayValue = this.searchValue = displayText !== args.displayText ? args.displayText - : this.createDisplayText(this.selection, [args.oldValue]); + : this.createDisplayText(super.selection, [args.oldValue]); } this._onChangeCallback(args.newValue); this._updateInput = true; @@ -541,7 +560,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co const filtered = this.filteredData.find(this.findMatch); // selecting null in primitive data returns undefined as the search text is '', but the item is null - if (filtered === undefined && this.selectedItem !== null || !this.selection.length) { + if (filtered === undefined && this.selectedItem !== null || !super.selection.length) { this.clear(); } }