diff --git a/CHANGELOG.md b/CHANGELOG.md index d7dae1f8cf0..20489f2d909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,12 @@ All notable changes for each version of this project will be documented in this - `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` - The `draggable` attribute is no longer required to be set on interactable elements, if a column header is templated and the Column Moving is enabled in order for handlers for any event to be triggered. Now `draggable='false'` can be used as an addition if the user shouldn't be able to drag a column by that element, but even if omitted `click` events for example will trigger now. - **Behavioral Change** When there are already grouped columns, the group drop area now shows after dragging of a column starts and not when only click actions are performed. +- `IgxCombo`, `IgxSimpleCombo`: + - **Breaking Change** The `selection` property returns an array of the selected items even when a value key is provided and the `value` property returns an array of value keys instead of display keys. Automatic migrations are available and will be applied on `ng update`. + +### New Features +- `IgxCombo`, `IgxSimpleCombo` + - Added new property `displayValue` that returns array of display keys. ## 16.0.0 diff --git a/projects/igniteui-angular/migrations/update-16_1_0/changes/members.json b/projects/igniteui-angular/migrations/update-16_1_0/changes/members.json new file mode 100644 index 00000000000..78ae19d9eae --- /dev/null +++ b/projects/igniteui-angular/migrations/update-16_1_0/changes/members.json @@ -0,0 +1,21 @@ +{ + "$schema": "../../common/schema/members-changes.schema.json", + "changes": [ + { + "member": "value", + "replaceWith": "displayValue", + "definedIn": [ + "IgxComboComponent", + "IgxSimpleComboComponent" + ] + }, + { + "member": "selection", + "replaceWith": "value", + "definedIn": [ + "IgxComboComponent", + "IgxSimpleComboComponent" + ] + } + ] +} diff --git a/projects/igniteui-angular/migrations/update-16_1_0/index.spec.ts b/projects/igniteui-angular/migrations/update-16_1_0/index.spec.ts index c9ce285b011..68c1df85ede 100644 --- a/projects/igniteui-angular/migrations/update-16_1_0/index.spec.ts +++ b/projects/igniteui-angular/migrations/update-16_1_0/index.spec.ts @@ -88,4 +88,48 @@ describe(`Update to ${version}`, () => { `); }); + + it('Should properly rename value property to displayValue and selection to value', async () => { + pending('set up tests for migrations through lang service'); + appTree.create('/testSrc/appPrefix/component/test.component.ts', + ` + import { IgxComboComponent } from 'igniteui-angular'; + export class MyClass { + @ViewChild(IgxComboComponent, { read: IgxComboComponent }) + public combo: IgxComboComponent; + @ViewChild(IgxSimpleComboComponent, { read: IgxSimpleComboComponent }) + public simpleCombo: IgxSimpleComboComponent; + public ngAfterViewInit() { + const comboDisplayValue = combo.value; + const comboSelectionValue = combo.selection; + const simpleComboDisplayValue = simpleCombo.value; + const simpleComboSelectionValue = simpleCombo.selection; + } + } + `); + + const tree = await schematicRunner + .runSchematicAsync(migrationName, {}, appTree) + .toPromise(); + + expect( + tree.readContent('/testSrc/appPrefix/component/test.component.ts') + ).toEqual( + ` + import { IgxComboComponent } from 'igniteui-angular'; + export class MyClass { + @ViewChild(IgxComboComponent, { read: IgxComboComponent }) + public combo: IgxComboComponent; + @ViewChild(IgxSimpleComboComponent, { read: IgxSimpleComboComponent }) + public simpleCombo: IgxSimpleComboComponent; + public ngAfterViewInit() { + const comboDisplayValue = combo.displayValue; + const comboSelectionValue = combo.value; + const simpleComboDisplayValue = simpleCombo.displayValue; + const simpleComboSelectionValue = simpleCombo.value; + } + } + ` + ); + }); }); diff --git a/projects/igniteui-angular/src/lib/combo/combo.common.ts b/projects/igniteui-angular/src/lib/combo/combo.common.ts index 5438c032edd..63a7c9c9de9 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.common.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.common.ts @@ -812,17 +812,29 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement } /** - * The text displayed in the combo input + * The value of the selected item in the combo * * ```typescript * // get * let comboValue = this.combo.value; * ``` */ - public get value(): string { + public get value(): any[] { return this._value; } + /** + * The text displayed in the combo input + * + * ```typescript + * // get + * let comboDisplayValue = this.combo.displayValue; + * ``` + */ + public get displayValue(): string[] { + return this._displayValue ? this._displayValue.split(', ') : []; + } + /** * Defines the current state of the virtualized data. It contains `startIndex` and `chunkSize` * @@ -923,7 +935,8 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement this._filteringOptions = value; } protected _data = []; - protected _value = ''; + protected _value = []; + protected _displayValue = ''; protected _groupKey = ''; protected _searchValue = ''; protected _filteredData = []; @@ -1024,7 +1037,7 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement * ``` */ public toggle(): void { - if (this.collapsed && this._value.length !== 0) { + if (this.collapsed && this._displayValue.length !== 0) { this.filterValue = ''; this.cdr.detectChanges(); } @@ -1044,7 +1057,7 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement * ``` */ public open(): void { - if (this.collapsed && this._value.length !== 0) { + if (this.collapsed && this._displayValue.length !== 0) { this.filterValue = ''; this.cdr.detectChanges(); } @@ -1082,7 +1095,7 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement */ public get selection() { const items = Array.from(this.selectionService.get(this.id)); - return items; + return this.convertKeysToItems(items); } /** @@ -1280,7 +1293,7 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement /** if there is a valueKey - map the keys to data items, else - just return the keys */ protected convertKeysToItems(keys: any[]) { - if (this.comboAPI.valueKey === null) { + if (this.valueKey === null || this.valueKey === undefined) { return keys; } diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.html b/projects/igniteui-angular/src/lib/combo/combo.component.html index 8bd5c0db045..34b7a94ed36 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.html +++ b/projects/igniteui-angular/src/lib/combo/combo.component.html @@ -8,7 +8,7 @@ - - diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.spec.ts b/projects/igniteui-angular/src/lib/combo/combo.component.spec.ts index 460b768a956..47eee86153b 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.spec.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.component.spec.ts @@ -108,13 +108,14 @@ describe('igxCombo', () => { combo.registerOnTouched(mockNgControl.registerOnTouchedCb); // writeValue - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); mockSelection.get.and.returnValue(new Set(['test'])); spyOnProperty(combo, 'isRemote').and.returnValue(false); combo.writeValue(['test']); expect(mockNgControl.registerOnChangeCb).not.toHaveBeenCalled(); expect(mockSelection.select_items).toHaveBeenCalledWith(combo.id, ['test'], true); - expect(combo.value).toBe('test'); + expect(combo.displayValue).toEqual(['test']); + expect(combo.value).toEqual(['test']); // setDisabledState combo.setDisabledState(true); @@ -241,29 +242,40 @@ describe('igxCombo', () => { combo.dropdown = dropdown; spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length); - const selectedItems = [combo.data[0].country]; + const selectedItems = [combo.data[0]]; + const selectedValues = [combo.data[0].country]; combo.setSelectedItem('UK', true); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedValues); combo.setSelectedItem('Germany', true); - selectedItems.push(combo.data[2].country); + selectedItems.push(combo.data[2]); + selectedValues.push(combo.data[2].country); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedValues); selectedItems.pop(); + selectedValues.pop(); combo.setSelectedItem('Germany', false); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedValues); selectedItems.pop(); + selectedValues.pop(); combo.setSelectedItem('UK', false); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedValues); combo.valueKey = null; selectedItems.push(combo.data[5]); combo.setSelectedItem(combo.data[5], true); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); selectedItems.push(combo.data[1]); combo.setSelectedItem(combo.data[1], true); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); selectedItems.pop(); combo.setSelectedItem(combo.data[1], false); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); }); it('should set selectedItems correctly on selectItems method call', () => { const selectionService = new IgxSelectionAPIService(); @@ -278,18 +290,24 @@ describe('igxCombo', () => { combo.select([], false); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); combo.select([], true); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); const selectedItems = combo.data.slice(0, 3); combo.select(combo.data.slice(0, 3), true); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); combo.select([], false); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); selectedItems.push(combo.data[3]); combo.select([combo.data[3]], false); expect(combo.selection).toEqual(combo.data.slice(0, 4)); + expect(combo.value).toEqual(combo.data.slice(0, 4)); combo.select([], true); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); }); it('should emit owner on `opening` and `closing`', () => { combo = new IgxComboComponent(elementRef, mockCdr, mockSelection as any, mockComboService, @@ -525,6 +543,7 @@ describe('igxCombo', () => { combo.selectAllItems(true); expect(combo.selection).toEqual(data); + expect(combo.value).toEqual(data); expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(1); expect(combo.selectionChanging.emit).toHaveBeenCalledWith({ oldSelection: [], @@ -539,6 +558,7 @@ describe('igxCombo', () => { combo.deselectAllItems(true); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(2); expect(combo.selectionChanging.emit).toHaveBeenCalledWith({ oldSelection: data, @@ -688,7 +708,7 @@ describe('igxCombo', () => { const item = combo.data.slice(0, 1); combo.select(item, true); combo.handleClearItems(spyObj); - expect(combo.value).toEqual(item[0]); + expect(combo.displayValue).toEqual([item[0]]); }); it('should allow canceling and overwriting of item addition', fakeAsync(() => { @@ -1296,15 +1316,17 @@ describe('igxCombo', () => { const spyObj = jasmine.createSpyObj('event', ['stopPropagation']); combo.toggle(); combo.select([selectedItems[0][combo.valueKey], selectedItems[1][combo.valueKey]]); - expect(combo.value).toEqual(`${selectedItems[0][combo.displayKey]}, ${selectedItems[1][combo.displayKey]}`); - expect(combo.selection).toEqual([selectedItems[0][combo.valueKey], selectedItems[1][combo.valueKey]]); + expect(combo.displayValue).toEqual([`${selectedItems[0][combo.displayKey]}`, `${selectedItems[1][combo.displayKey]}`]); + expect(combo.selection).toEqual([selectedItems[0], selectedItems[1]]); + expect(combo.value).toEqual([selectedItems[0][combo.valueKey], selectedItems[1][combo.valueKey]]); // Clear items while they are in view combo.handleClearItems(spyObj); expect(combo.selection).toEqual([]); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); + expect(combo.value).toEqual([]); selectedItems = [combo.data[2], combo.data[3]]; combo.select([selectedItems[0][combo.valueKey], selectedItems[1][combo.valueKey]]); - expect(combo.value).toEqual(`${selectedItems[0][combo.displayKey]}, ${selectedItems[1][combo.displayKey]}`); + expect(combo.displayValue).toEqual([`${selectedItems[0][combo.displayKey]}`, `${selectedItems[1][combo.displayKey]}`]); // Scroll selected items out of view combo.virtualScrollContainer.scrollTo(40); @@ -1312,21 +1334,23 @@ describe('igxCombo', () => { fixture.detectChanges(); combo.handleClearItems(spyObj); expect(combo.selection).toEqual([]); - expect(combo.value).toBe(''); + expect(combo.value).toEqual([]); + expect(combo.displayValue).toEqual([]); combo.select([combo.data[7][combo.valueKey]]); - expect(combo.value).toBe(combo.data[7][combo.displayKey]); + expect(combo.displayValue).toEqual([combo.data[7][combo.displayKey]]); }); it('should add selected items to the input when data is loaded', async() => { expect(combo.selection.length).toEqual(0); - expect(combo.value).toEqual(''); + expect(combo.value).toEqual([]); // current combo data - id: 0 - 9 // select item that is not present in the data source yet combo.select([9, 19]); - expect(combo.selection.length).toEqual(2); + expect(combo.selection.length).toEqual(1); + expect(combo.value.length).toEqual(2); const firstItem = combo.data[combo.data.length - 1]; - expect(combo.value).toEqual(firstItem[combo.displayKey]); + expect(combo.displayValue).toEqual([firstItem[combo.displayKey]]); combo.toggle(); @@ -1336,7 +1360,7 @@ describe('igxCombo', () => { fixture.detectChanges(); const secondItem = combo.data[combo.data.length - 1]; - expect(combo.value).toEqual(`${firstItem[combo.displayKey]}, ${secondItem[combo.displayKey]}`); + expect(combo.displayValue).toEqual([`${firstItem[combo.displayKey]}`, `${secondItem[combo.displayKey]}`]); }); }); describe('Binding to ngModel tests: ', () => { @@ -1352,7 +1376,8 @@ describe('igxCombo', () => { component.selectedItems = [0, 2]; fixture.detectChanges(); tick(); - expect(combo.selection).toEqual([combo.data[0][combo.valueKey], combo.data[2][combo.valueKey]]); + expect(combo.selection).toEqual([combo.data[0], combo.data[2]]); + expect(combo.value).toEqual([combo.data[0][combo.valueKey], combo.data[2][combo.valueKey]]); combo.select([combo.data[4][combo.valueKey]]); fixture.detectChanges(); expect(component.selectedItems).toEqual([0, 2, 4]); @@ -1362,6 +1387,7 @@ describe('igxCombo', () => { fixture.detectChanges(); tick(); expect(combo.selection).toEqual([combo.data[0], combo.data[2]]); + expect(combo.value).toEqual([combo.data[0], combo.data[2]]); combo.select([combo.data[4]]); fixture.detectChanges(); expect(component.selectedItems).toEqual([combo.data[0], combo.data[2], combo.data[4]]); @@ -1373,6 +1399,7 @@ describe('igxCombo', () => { tick(); const data = fixture.componentInstance.items; expect(combo.selection).toEqual(component.selectedItems); + expect(combo.value).toEqual(component.selectedItems); combo.select([...data].splice(1, 3), true); fixture.detectChanges(); expect(fixture.componentInstance.selectedItems).toEqual([...data].splice(1, 3)); @@ -1906,6 +1933,7 @@ describe('igxCombo', () => { expect(input.nativeElement.value).toEqual(''); expect(combo.selection.length).toEqual(0); + expect(combo.value.length).toEqual(0); combo.toggle(); fixture.detectChanges(); expect(combo.dropdown.items[1].selected).toBeFalsy(); @@ -1949,7 +1977,8 @@ describe('igxCombo', () => { const selectedItem_1 = dropdown.items[1]; simulateComboItemClick(1); - expect(combo.selection[0]).toEqual(selectedItem_1.value.field); + expect(combo.selection[0]).toEqual(selectedItem_1.value); + expect(combo.value[0]).toEqual(selectedItem_1.value[combo.valueKey]); expect(selectedItem_1.selected).toBeTruthy(); expect(selectedItem_1.element.nativeElement.classList.contains(CSS_CLASS_SELECTED)).toBeTruthy(); expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(1); @@ -1967,7 +1996,8 @@ describe('igxCombo', () => { const selectedItem_2 = dropdown.items[5]; simulateComboItemClick(5); - expect(combo.selection[1]).toEqual(selectedItem_2.value.field); + expect(combo.selection[1]).toEqual(selectedItem_2.value); + expect(combo.value[1]).toEqual(selectedItem_2.value[combo.valueKey]); expect(selectedItem_2.selected).toBeTruthy(); expect(selectedItem_2.element.nativeElement.classList.contains(CSS_CLASS_SELECTED)).toBeTruthy(); expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(2); @@ -2030,8 +2060,9 @@ describe('igxCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0'); - expect(combo.selection).toEqual([0]); + expect(combo.displayValue).toEqual(['0']); + expect(combo.value).toEqual([0]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }]); combo.open(); fixture.detectChanges(); @@ -2040,8 +2071,9 @@ describe('igxCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0, false'); - expect(combo.selection).toEqual([0, false]); + expect(combo.displayValue).toEqual(['0', 'false']); + expect(combo.value).toEqual([0, false]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }, { field: 'false', value: false }]); combo.open(); fixture.detectChanges(); @@ -2050,8 +2082,9 @@ describe('igxCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0, false, '); - expect(combo.selection).toEqual([0, false, '']); + expect(combo.displayValue).toEqual(['0', 'false', '']); + expect(combo.value).toEqual([0, false, '']); + expect(combo.selection).toEqual([{ field: '0', value: 0 }, { field: 'false', value: false }, { field: '', value: '' }]); combo.open(); fixture.detectChanges(); @@ -2060,8 +2093,9 @@ describe('igxCombo', () => { item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0, false, , null'); - expect(combo.selection).toEqual([0, false, '', null]); + expect(combo.displayValue).toEqual(['0', 'false', '', 'null']); + expect(combo.value).toEqual([0, false, '', null]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }, { field: 'false', value: false }, { field: '', value: '' }, { field: 'null', value: null }]); combo.open(); fixture.detectChanges(); @@ -2070,8 +2104,10 @@ describe('igxCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0, false, , null, NaN'); - expect(combo.selection).toEqual([0, false, '', null, NaN]); + expect(combo.displayValue).toEqual(['0', 'false', '', 'null', 'NaN']); + expect(combo.value).toEqual([0, false, '', null, NaN]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }, { field: 'false', value: false }, + { field: '', value: '' }, { field: 'null', value: null }, { field: 'NaN', value: NaN }]); combo.open(); fixture.detectChanges(); @@ -2080,8 +2116,10 @@ describe('igxCombo', () => { item6.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0, false, , null, NaN'); - expect(combo.selection).toEqual([0, false, '', null, NaN]); + expect(combo.displayValue).toEqual(['0', 'false', '', 'null', 'NaN']); + expect(combo.value).toEqual([0, false, '', null, NaN]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }, { field: 'false', value: false }, + { field: '', value: '' }, { field: 'null', value: null }, { field: 'NaN', value: NaN }]); }); it('should select falsy values except "undefined" with "writeValue" method', () => { combo.valueKey = 'value'; @@ -2096,29 +2134,35 @@ describe('igxCombo', () => { ]; combo.writeValue([0]); - expect(combo.selection).toEqual([0]); - expect(combo.value).toBe('0'); + expect(combo.selection).toEqual([{ field: '0', value: 0 }]); + expect(combo.value).toEqual([0]); + expect(combo.displayValue).toEqual(['0']); combo.writeValue([false]); - expect(combo.selection).toEqual([false]); - expect(combo.value).toBe('false'); + expect(combo.selection).toEqual([{ field: 'false', value: false }]); + expect(combo.value).toEqual([false]); + expect(combo.displayValue).toEqual(['false']); combo.writeValue(['']); - expect(combo.selection).toEqual(['']); - expect(combo.value).toBe('empty'); + expect(combo.selection).toEqual([{ field: 'empty', value: '' }]); + expect(combo.value).toEqual(['']); + expect(combo.displayValue).toEqual(['empty']); combo.writeValue([null]); - expect(combo.selection).toEqual([null]); - expect(combo.value).toBe('null'); + expect(combo.selection).toEqual([{ field: 'null', value: null }]); + expect(combo.value).toEqual([null]); + expect(combo.displayValue).toEqual(['null']); combo.writeValue([NaN]); - expect(combo.selection).toEqual([NaN]); - expect(combo.value).toBe('NaN'); + expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); + expect(combo.value).toEqual([NaN]); + expect(combo.displayValue).toEqual(['NaN']); // should not select undefined combo.writeValue([undefined]); expect(combo.selection).toEqual([]); - expect(combo.value).toBe(''); + expect(combo.value).toEqual([]); + expect(combo.displayValue).toEqual([]); }); it('should select values that have spaces as prefixes/suffixes', fakeAsync(() => { combo.displayKey = combo.valueKey = 'value'; @@ -2150,7 +2194,7 @@ describe('igxCombo', () => { combo.onBlur(); tick(); fixture.detectChanges(); - expect(combo.value).toBe('Mississippi '); + expect(combo.displayValue).toEqual(['Mississippi ']); })); it('should prevent selection when selectionChanging is cancelled', () => { spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.cancel = true); @@ -2208,13 +2252,15 @@ describe('igxCombo', () => { combo.select([1]); fixture.detectChanges(); - expect(combo.selection).toEqual([1]); - expect(combo.value).toBe('Selected Count: 1'); + expect(combo.selection).toEqual([{ key: 1, value: 'One' }]); + expect(combo.value).toEqual([1]); + expect(combo.displayValue).toEqual(['Selected Count: 1']); combo.deselect([1]); expect(combo.selection).toEqual([]); - expect(combo.value).toBe('Selected Count: 0'); + expect(combo.value).toEqual([]); + expect(combo.displayValue).toEqual(['Selected Count: 0']); }); }); describe('Grouping tests: ', () => { @@ -2595,7 +2641,8 @@ describe('igxCombo', () => { combo.toggle(); fixture.detectChanges(); expect(combo.selection).toEqual([]); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.comboInput.nativeElement.value).toEqual(''); combo.searchValue = 'New '; @@ -2606,13 +2653,15 @@ describe('igxCombo', () => { addItemButton.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.selection).toEqual(['New ']); + expect(combo.selection).toEqual([{ field: 'New ', region: 'Other' }]); + expect(combo.value).toEqual(['New ']); expect(combo.comboInput.nativeElement.value).toEqual('New '); const clearButton = fixture.debugElement.query(By.css(`.${CSS_CLASS_CLEARBUTTON}`)); clearButton.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.comboInput.nativeElement.value).toEqual(''); }); it('should remove ADD button when search value matches an already selected item and custom values are enabled ', () => { @@ -2646,7 +2695,7 @@ describe('igxCombo', () => { combo.handleInputChange(); fixture.detectChanges(); expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); expect(combo.isAddButtonVisible()).toBeTruthy(); combo.handleKeyUp(UIInteractions.getKeyboardEvent('keyup', 'ArrowDown')); @@ -2655,13 +2704,13 @@ describe('igxCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Space', dropdownContent); fixture.detectChanges(); expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); expect(combo.isAddButtonVisible()).toBeTruthy(); UIInteractions.triggerEventHandlerKeyDown('Enter', dropdownContent); fixture.detectChanges(); expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual('My New Custom Item'); + expect(combo.displayValue).toEqual(['My New Custom Item']); }); it(`should handle click on "Add Item" properly`, () => { combo.allowCustomValues = true; @@ -2672,7 +2721,7 @@ describe('igxCombo', () => { combo.handleInputChange(); fixture.detectChanges(); expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); expect(combo.isAddButtonVisible()).toBeTruthy(); combo.handleKeyUp(UIInteractions.getKeyboardEvent('keyup', 'ArrowDown')); @@ -2682,13 +2731,13 @@ describe('igxCombo', () => { fixture.detectChanges(); // SPACE does not add item to collection expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); const focusedItem = fixture.debugElement.query(By.css(`.${CSS_CLASS_FOCUSED}`)); focusedItem.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); expect(combo.collapsed).toBeFalsy(); - expect(combo.value).toEqual('My New Custom Item'); + expect(combo.displayValue).toEqual(['My New Custom Item']); }); it('should enable/disable filtering at runtime', fakeAsync(() => { combo.open(); // Open combo - all data items are in filteredData @@ -2895,6 +2944,7 @@ describe('igxCombo', () => { const comboFormReference = fixture.componentInstance.reactiveForm.controls.townCombo; expect(comboFormReference).toBeDefined(); expect(combo.selection).toEqual(comboFormReference.value); + expect(combo.value).toEqual(comboFormReference.value); expect(combo.selection.length).toEqual(1); expect(combo.selection[0].field).toEqual('Connecticut'); expect(combo.valid).toEqual(IgxComboState.INITIAL); @@ -2926,6 +2976,7 @@ describe('igxCombo', () => { const comboFormReference = fixture.componentInstance.reactiveForm.controls.townCombo; expect(comboFormReference).toBeDefined(); expect(combo.selection).toEqual(comboFormReference.value); + expect(combo.value).toEqual(comboFormReference.value); expect(combo.selection.length).toEqual(1); expect(combo.selection[0].field).toEqual('Connecticut'); expect(combo.valid).toEqual(IgxComboState.INITIAL); @@ -2988,11 +3039,13 @@ describe('igxCombo', () => { const comboFormReference = form.controls.townCombo; expect(comboFormReference).toBeDefined(); expect(combo.selection).toEqual(comboFormReference.value); + expect(combo.value).toEqual(comboFormReference.value); // Form -> Combo comboFormReference.setValue([{ field: 'Missouri', region: 'West North Central' }]); fixture.detectChanges(); expect(combo.selection).toEqual([{ field: 'Missouri', region: 'West North Central' }]); + expect(combo.value).toEqual([{ field: 'Missouri', region: 'West North Central' }]); // Combo -> Form combo.select([{ field: 'South Carolina', region: 'South Atlantic' }], true); @@ -3109,8 +3162,9 @@ describe('igxCombo', () => { tick(); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); - expect(combo.selection).toEqual(['Missouri']); - expect(combo.value).toEqual('Missouri'); + expect(combo.selection).toEqual([{ field: 'Missouri', region: 'West North Central' }]); + expect(combo.value).toEqual(['Missouri']); + expect(combo.displayValue).toEqual(['Missouri']); expect(model.valid).toBeTrue(); expect(model.touched).toBeFalse(); @@ -3118,8 +3172,9 @@ describe('igxCombo', () => { fixture.detectChanges(); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); - expect(combo.selection).toEqual(['Missouri']); - expect(combo.value).toEqual('Missouri'); + expect(combo.selection).toEqual([{ field: 'Missouri', region: 'West North Central' }]); + expect(combo.value).toEqual(['Missouri']); + expect(combo.displayValue).toEqual(['Missouri']); expect(model.valid).toBeTrue(); expect(model.touched).toBeFalse(); @@ -3129,7 +3184,8 @@ describe('igxCombo', () => { expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); expect(combo.selection).toEqual([]); - expect(combo.value).toEqual(''); + expect(combo.value).toEqual([]); + expect(combo.displayValue).toEqual([]); expect(model.valid).toBeFalse(); expect(model.touched).toBeFalse(); expect(model.dirty).toBeFalse(); @@ -3147,8 +3203,9 @@ describe('igxCombo', () => { tick(); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); - expect(combo.selection).toEqual(['New Jersey']); - expect(combo.value).toEqual('New Jersey'); + expect(combo.selection).toEqual([{ field: 'New Jersey', region: 'Mid-Atlan' }]); + expect(combo.value).toEqual(['New Jersey']); + expect(combo.displayValue).toEqual(['New Jersey']); expect(model.valid).toBeTrue(); expect(model.touched).toBeTrue(); expect(model.dirty).toBeFalse(); diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.ts b/projects/igniteui-angular/src/lib/combo/combo.component.ts index ef5f38f6ee1..d9c63fabdf3 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.component.ts @@ -180,7 +180,7 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie * @hidden @internal */ public get inputEmpty(): boolean { - return !this.value && !this.placeholder; + return this.displayValue.length === 0 && !this.placeholder; } /** @hidden @internal */ @@ -262,13 +262,15 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie const oldSelection = this.selection; this.selectionService.select_items(this.id, selection, true); this.cdr.markForCheck(); - this._value = this.createDisplayText(this.selection, oldSelection); + this._displayValue = this.createDisplayText(this.selection, oldSelection); + this._value = this.valueKey ? this.selection.map(item => item[this.valueKey]) : this.selection; } /** @hidden @internal */ public override ngDoCheck(): void { if (this.data?.length && this.selection.length) { - this._value = this._displayText || this.createDisplayText(this.selection, []); + this._displayValue = this._displayText || this.createDisplayText(this.selection, []); + this._value = this.valueKey ? this.selection.map(item => item[this.valueKey]) : this.selection; } super.ngDoCheck(); } @@ -430,7 +432,7 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie const added = diffInSets(newSelection, this.selectionService.get(this.id)); const newSelectionAsArray = Array.from(newSelection); const oldSelectionAsArray = Array.from(this.selectionService.get(this.id) || []); - const displayText = this.createDisplayText(newSelectionAsArray, oldSelectionAsArray); + const displayText = this.createDisplayText(this.convertKeysToItems(newSelectionAsArray), oldSelectionAsArray); const args: IComboSelectionChangingEventArgs = { newSelection: newSelectionAsArray, oldSelection: oldSelectionAsArray, @@ -444,10 +446,11 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie this.selectionChanging.emit(args); if (!args.cancel) { this.selectionService.select_items(this.id, args.newSelection, true); + this._value = args.newSelection; if (displayText !== args.displayText) { - this._value = this._displayText = args.displayText; + this._displayValue = this._displayText = args.displayText; } else { - this._value = this.createDisplayText(args.newSelection, args.oldSelection); + this._displayValue = this.createDisplayText(this.selection, args.oldSelection); } this._onChangeCallback(args.newSelection); } else if (this.isRemote) { @@ -456,15 +459,16 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie } protected createDisplayText(newSelection: any[], oldSelection: any[]) { + const selection = this.valueKey ? newSelection.map(item => item[this.valueKey]) : newSelection; return this.isRemote - ? this.getRemoteSelection(newSelection, oldSelection) + ? this.getRemoteSelection(selection, oldSelection) : this.concatDisplayText(newSelection); } /** Returns a string that should be populated in the combo's text box */ private concatDisplayText(selection: any[]): string { const value = this.displayKey !== null && this.displayKey !== undefined ? - this.convertKeysToItems(selection).map(entry => entry[this.displayKey]).join(', ') : + selection.map(entry => entry[this.displayKey]).join(', ') : selection.join(', '); return value; } 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 32ca3635014..f01f5124e18 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 @@ -12,7 +12,7 @@ - { combo.dropdown = dropdown; spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length); - const selectedItems = [combo.data[0].country]; + const selectedItems = [combo.data[0]]; + const selectedValues = [combo.data[0].country]; combo.select('UK'); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedValues); combo.select('Germany'); - selectedItems.push(combo.data[2].country); + 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(); combo.valueKey = null; // without valueKey selectedItems.push(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]); combo.select(combo.data[1]); expect(combo.selection).toEqual(selectedItems); + expect(combo.value).toEqual(selectedItems); }); it('should emit owner on `opening` and `closing`', () => { combo = new IgxSimpleComboComponent(elementRef, mockCdr, mockSelection as any, mockComboService, @@ -428,7 +435,7 @@ describe('IgxSimpleCombo', () => { const item = combo.data.slice(0, 1); combo.select(item); combo.handleClear(spyObj); - expect(combo.value).toEqual(item[0]); + expect(combo.displayValue).toEqual([item[0]]); }); }); @@ -717,7 +724,8 @@ describe('IgxSimpleCombo', () => { component.selectedItem = 1; fixture.detectChanges(); tick(); - expect(combo.selection).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); @@ -732,6 +740,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); tick(); 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]); @@ -746,9 +755,10 @@ describe('IgxSimpleCombo', () => { combo.select('Three'); fixture.detectChanges(); expect(combo.selection).toEqual(['Three']); + expect(combo.value).toEqual(['Three']); combo.handleClear(new MouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); })); it('should properly bind to values w/o valueKey', fakeAsync(() => { @@ -761,6 +771,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); tick(); expect(combo.selection).toEqual([component.selectedItem]); + expect(combo.value).toEqual([component.selectedItem]); combo.select('Three'); fixture.detectChanges(); expect(fixture.componentInstance.selectedItem).toEqual('Three'); @@ -777,15 +788,17 @@ describe('IgxSimpleCombo', () => { combo.toggle(); combo.select(combo.data[1][combo.valueKey]); - expect(combo.value).toEqual(`${selectedItem[combo.displayKey]}`); - expect(combo.selection).toEqual([selectedItem[combo.valueKey]]); + expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); + 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.value).toBe(''); + expect(combo.displayValue).toEqual([]); + expect(combo.value).toEqual([]); selectedItem = combo.data[2]; combo.select(combo.data[2][combo.valueKey]); - expect(combo.value).toEqual(`${selectedItem[combo.displayKey]}`); + expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); // Scroll selected items out of view combo.virtualScrollContainer.scrollTo(40); @@ -793,9 +806,10 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); combo.handleClear(spyObj); expect(combo.selection).toEqual([]); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); + expect(combo.value).toEqual([]); combo.select(combo.data[7][combo.valueKey]); - expect(combo.value).toBe(combo.data[7][combo.displayKey]); + expect(combo.displayValue).toEqual([combo.data[7][combo.displayKey]]); })); }); @@ -914,12 +928,12 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerKeyDownEvtUponElem('Enter', input.nativeElement); expect(combo.selection.length).toEqual(1); - expect(combo.value).toEqual('Wisconsin'); + expect(combo.displayValue).toEqual(['Wisconsin']); UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); expect(combo.selection.length).toEqual(1); - expect(combo.value).toEqual('Wisconsin'); + expect(combo.displayValue).toEqual(['Wisconsin']); }); it('should display the AddItem button when allowCustomValues is true and there is a partial match', fakeAsync(() => { @@ -1111,7 +1125,7 @@ describe('IgxSimpleCombo', () => { expect((combo as any).clearSelection).toHaveBeenCalledOnceWith(true); expect(combo.dropdown.closing.emit).toHaveBeenCalledTimes(1); - expect(combo.value).toBeFalsy(); + expect(combo.displayValue).toEqual([]); }); it('should not clear the selection and input on blur with a match', () => { @@ -1127,6 +1141,7 @@ describe('IgxSimpleCombo', () => { expect(combo.selection.length).toBe(1); expect(combo.selection[0]).toEqual('Apple'); + expect(combo.value[0]).toEqual('Apple'); combo.open(); fixture.detectChanges(); @@ -1134,7 +1149,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.value).toEqual('Apple'); + expect(combo.displayValue).toEqual(['Apple']); expect(combo.selection.length).toEqual(1); }); @@ -1151,7 +1166,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.value).toEqual(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection.length).toEqual(0); }); @@ -1203,7 +1218,7 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); combo.open(); fixture.detectChanges(); @@ -1212,7 +1227,7 @@ describe('IgxSimpleCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('val2'); + expect(combo.displayValue).toEqual(['val2']); combo.open(); fixture.detectChanges(); @@ -1221,7 +1236,7 @@ describe('IgxSimpleCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); combo.open(); fixture.detectChanges(); @@ -1230,7 +1245,7 @@ describe('IgxSimpleCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); }); it('should select falsy values except "undefined"', () => { @@ -1252,8 +1267,9 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('0'); - expect(combo.selection).toEqual([ 0 ]); + expect(combo.displayValue).toEqual(['0']); + expect(combo.value).toEqual([ 0 ]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }]); combo.open(); fixture.detectChanges(); @@ -1262,8 +1278,9 @@ describe('IgxSimpleCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('false'); - expect(combo.selection).toEqual([ false ]); + expect(combo.displayValue).toEqual(['false']); + expect(combo.value).toEqual([ false ]); + expect(combo.selection).toEqual([{ field: 'false', value: false }]); combo.open(); fixture.detectChanges(); @@ -1272,8 +1289,9 @@ describe('IgxSimpleCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); - expect(combo.selection).toEqual([ '' ]); + expect(combo.displayValue).toEqual([]); + expect(combo.value).toEqual([ '' ]); + expect(combo.selection).toEqual([{ field: '', value: '' }]); combo.open(); fixture.detectChanges(); @@ -1282,8 +1300,9 @@ describe('IgxSimpleCombo', () => { item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('null'); - expect(combo.selection).toEqual([ null ]); + expect(combo.displayValue).toEqual(['null']); + expect(combo.value).toEqual([ null ]); + expect(combo.selection).toEqual([{ field: 'null', value: null }]); combo.open(); fixture.detectChanges(); @@ -1292,11 +1311,12 @@ describe('IgxSimpleCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('NaN'); - expect(combo.selection).toEqual([ NaN ]); + expect(combo.displayValue).toEqual(['NaN']); + expect(combo.value).toEqual([ NaN ]); + expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); // should not select "undefined" - // combo.value & combo.selection equal the values from the previous selection + // combo.displayValue & combo.selection equal the values from the previous selection combo.open(); fixture.detectChanges(); const item6 = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_DROPDOWNLISTITEM}`))[5]; @@ -1304,8 +1324,9 @@ describe('IgxSimpleCombo', () => { item6.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe('NaN'); - expect(combo.selection).toEqual([ NaN ]); + expect(combo.displayValue).toEqual(['NaN']); + expect(combo.value).toEqual([ NaN ]); + expect(combo.selection).toEqual([{ field: 'NaN', value: NaN }]); }); it('should select falsy values except "undefined" with "writeValue" method', () => { @@ -1321,29 +1342,35 @@ describe('IgxSimpleCombo', () => { ]; combo.writeValue(0); - expect(combo.selection).toEqual([0]); - expect(combo.value).toBe('0'); + expect(combo.value).toEqual([0]); + expect(combo.selection).toEqual([{ field: '0', value: 0 }]); + expect(combo.displayValue).toEqual(['0']); combo.writeValue(false); - expect(combo.selection).toEqual([false]); - expect(combo.value).toBe('false'); + expect(combo.value).toEqual([false]); + expect(combo.selection).toEqual([{ field: 'false', value: false }]); + expect(combo.displayValue).toEqual(['false']); combo.writeValue(''); - expect(combo.selection).toEqual(['']); - expect(combo.value).toBe('empty'); + expect(combo.value).toEqual(['']); + expect(combo.selection).toEqual([{ field: 'empty', value: '' }]); + expect(combo.displayValue).toEqual(['empty']); combo.writeValue(null); - expect(combo.selection).toEqual([null]); - expect(combo.value).toBe('null'); + expect(combo.value).toEqual([null]); + expect(combo.selection).toEqual([{ field: 'null', value: null }]); + expect(combo.displayValue).toEqual(['null']); combo.writeValue(NaN); - expect(combo.selection).toEqual([NaN]); - expect(combo.value).toBe('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).toBe(''); + expect(combo.displayValue).toEqual([]); }); it('should toggle dropdown list on clicking a templated toggle icon', fakeAsync(() => { @@ -1412,7 +1439,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); expect(combo.selection.length).toBe(1); - expect(combo.selection[0]).toEqual('Connecticut'); + expect(combo.selection[0]).toEqual({ field: 'Connecticut', region: 'New England' }); fixture.detectChanges(); combo.dropdown.close(); @@ -1463,7 +1490,7 @@ describe('IgxSimpleCombo', () => { combo.onBlur(); tick(); fixture.detectChanges(); - expect(combo.value).toBe('Ohio '); + expect(combo.displayValue).toEqual(['Ohio ']); })); }); @@ -1600,8 +1627,9 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1612,8 +1640,9 @@ describe('IgxSimpleCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1624,8 +1653,9 @@ describe('IgxSimpleCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1647,8 +1677,9 @@ describe('IgxSimpleCombo', () => { item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1659,8 +1690,9 @@ describe('IgxSimpleCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1685,20 +1717,23 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); combo.writeValue(null); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1717,20 +1752,23 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); combo.writeValue(null); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1762,8 +1800,9 @@ describe('IgxSimpleCombo', () => { { field: 'undefined', value: undefined }, ]; - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); @@ -1774,8 +1813,9 @@ describe('IgxSimpleCombo', () => { item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1786,8 +1826,9 @@ describe('IgxSimpleCombo', () => { item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1798,8 +1839,9 @@ describe('IgxSimpleCombo', () => { item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1810,8 +1852,9 @@ describe('IgxSimpleCombo', () => { fixture.componentInstance.reactiveForm.resetForm(); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); @@ -1822,8 +1865,9 @@ describe('IgxSimpleCombo', () => { item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1834,8 +1878,9 @@ describe('IgxSimpleCombo', () => { item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1850,8 +1895,9 @@ describe('IgxSimpleCombo', () => { { field: 'undefined', value: undefined }, ]; - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); @@ -1859,20 +1905,23 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); combo.writeValue(null); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); @@ -1883,8 +1932,9 @@ describe('IgxSimpleCombo', () => { fixture.componentInstance.reactiveForm.resetForm(); fixture.detectChanges(); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INITIAL); expect(combo.comboInput.valid).toEqual(IgxInputState.INITIAL); @@ -1892,20 +1942,23 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); combo.writeValue(null); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(''); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); combo.writeValue(undefined); - expect(combo.value).toBe(''); + expect(combo.displayValue).toEqual([]); expect(combo.selection).toEqual([]); + expect(combo.value).toEqual([]); expect(combo.valid).toEqual(IgxComboState.INVALID); expect(combo.comboInput.valid).toEqual(IgxInputState.INVALID); }); @@ -1980,7 +2033,7 @@ describe('IgxSimpleCombo', () => { const expectedOutput = 'One'; expect(input.nativeElement.value).toEqual(expectedOutput); })); - it('should not clear selection when bound to remote data and item is out of view', (async () => { + 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); @@ -1999,11 +2052,12 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.selection.length).toEqual(1); - expect(combo.value).toEqual(`${selectedItem[combo.displayKey]}`); - expect(combo.selection).toEqual([selectedItem[combo.valueKey]]); + expect(combo.selection.length).toEqual(0); + expect(combo.value.length).toEqual(1); + expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); + expect(combo.value).toEqual([selectedItem[combo.valueKey]]); })); - it('should set combo.value to empty string when bound to remote data and selected item\'s data is not present', (async () => { + 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); @@ -2012,8 +2066,9 @@ describe('IgxSimpleCombo', () => { // select item that is not present in the data source yet combo.select(15); - expect(combo.selection.length).toEqual(1); - expect(combo.value).toEqual(''); + expect(combo.selection.length).toEqual(0); + expect(combo.value.length).toEqual(1); + expect(combo.displayValue).toEqual([]); combo.toggle(); @@ -2023,7 +2078,7 @@ describe('IgxSimpleCombo', () => { fixture.detectChanges(); const selectedItem = combo.data[combo.data.length - 1]; - expect(combo.value).toEqual(`${selectedItem[combo.displayKey]}`); + expect(combo.displayValue).toEqual([`${selectedItem[combo.displayKey]}`]); })); }); }); 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 c63e8d5043f..74163986736 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 @@ -185,8 +185,9 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co const oldSelection = this.selection; this.selectionService.select_items(this.id, this.isValid(value) ? [value] : [], true); this.cdr.markForCheck(); - this._value = this.createDisplayText(this.selection, oldSelection); - this.filterValue = this._internalFilter = this._value?.toString(); + this._displayValue = this.createDisplayText(this.selection, oldSelection); + this._value = this.valueKey ? this.selection.map(item => item[this.valueKey]) : this.selection; + this.filterValue = this._internalFilter = this._displayValue?.toString(); } /** @hidden @internal */ @@ -246,7 +247,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co // and sets the selection to an invalid value in writeValue method if (!this.isValid(this.selectedItem)) { this.selectionService.clear(this.id); - this._value = ''; + this._displayValue = ''; } super.ngAfterViewInit(); @@ -254,8 +255,9 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co /** @hidden @internal */ public override ngDoCheck(): void { - if (this.data?.length && this.selection.length && !this._value) { - this._value = this.createDisplayText(this.selection, []); + 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; } super.ngDoCheck(); } @@ -443,7 +445,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co protected setSelection(newSelection: any): void { const newSelectionAsArray = newSelection ? Array.from(newSelection) as IgxComboItemComponent[] : []; const oldSelectionAsArray = Array.from(this.selectionService.get(this.id) || []); - const displayText = this.createDisplayText(newSelectionAsArray, oldSelectionAsArray); + const displayText = this.createDisplayText(this.convertKeysToItems(newSelectionAsArray), oldSelectionAsArray); const args: ISimpleComboSelectionChangingEventArgs = { newSelection: newSelectionAsArray[0], oldSelection: oldSelectionAsArray[0], @@ -461,10 +463,11 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co : []; argsSelection = Array.isArray(argsSelection) ? argsSelection : [argsSelection]; this.selectionService.select_items(this.id, argsSelection, true); + this._value = argsSelection; if (this._updateInput) { - this.comboInput.value = this._internalFilter = this._value = this.searchValue = displayText !== args.displayText + this.comboInput.value = this._internalFilter = this._displayValue = this.searchValue = displayText !== args.displayText ? args.displayText - : this.createDisplayText(argsSelection, [args.oldSelection]); + : this.createDisplayText(this.selection, [args.oldSelection]); } this._onChangeCallback(args.newSelection); this._updateInput = true; @@ -475,13 +478,14 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co protected createDisplayText(newSelection: any[], oldSelection: any[]): string { if (this.isRemote) { - return this.getRemoteSelection(newSelection, oldSelection); + const selection = this.valueKey ? newSelection.map(item => item[this.valueKey]) : newSelection; + return this.getRemoteSelection(selection, oldSelection); } if (this.displayKey !== null && this.displayKey !== undefined && newSelection.length > 0) { - return this.convertKeysToItems(newSelection).filter(e => e).map(e => e[this.displayKey])[0]?.toString() || ''; + return newSelection.filter(e => e).map(e => e[this.displayKey])[0]?.toString() || ''; } return newSelection[0]?.toString() || ''; @@ -541,7 +545,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co private clear(): void { this.clearSelection(true); - this.comboInput.value = this._internalFilter = this._value = this.searchValue = ''; + this.comboInput.value = this._internalFilter = this._displayValue = this.searchValue = ''; } private isValid(value: any): boolean {