From d617418384deb6310e3bf9974ca439c55070108b Mon Sep 17 00:00:00 2001 From: ddaribo Date: Wed, 19 Jun 2024 13:04:18 +0300 Subject: [PATCH 1/4] fix(combo): add test for combo in IgxGrid cell template --- .../simple-combo.component.spec.ts | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) 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 c9979a00f08..dbacaa362d3 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 @@ -16,6 +16,8 @@ import { AbsoluteScrollStrategy, AutoPositionStrategy, ConnectedPositioningStrat import { configureTestSuite } from '../test-utils/configure-suite'; import { UIInteractions, wait } from '../test-utils/ui-interactions.spec'; import { IgxSimpleComboComponent, ISimpleComboSelectionChangingEventArgs } from './public_api'; +import { IgxGridComponent } from '../grids/grid/grid.component'; +import { IGX_GRID_DIRECTIVES } from '../grids/grid/public_api'; const CSS_CLASS_COMBO = 'igx-combo'; @@ -2271,8 +2273,109 @@ describe('IgxSimpleCombo', () => { expect(input.nativeElement.value).toEqual('Product 5'); })); }); + + describe('Integration', () => { + let grid: IgxGridComponent; + + beforeAll(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + NoopAnimationsModule, + IgxSimpleComboInGridComponent + ] + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(IgxSimpleComboInGridComponent); + fixture.detectChanges(); + grid = fixture.componentInstance.grid; + }); + it('Combo in IgxGrid cell display template correctly handles selection - issue #14305', async () => { + const firstRecRegionCell = grid.gridAPI.get_cell_by_index(0, 'Region') as any; + let comboNativeEl = firstRecRegionCell.nativeElement.querySelector(SIMPLE_COMBO_ELEMENT); + const comboToggleButton = comboNativeEl.querySelector(`.${CSS_CLASS_TOGGLEBUTTON}`); + + UIInteractions.simulateClickEvent(comboToggleButton); + fixture.detectChanges(); + + const comboDropDownList = fixture.debugElement.query(By.css(`.${CSS_CLASS_DROPDOWNLIST}`)); + const firstItem = comboDropDownList.nativeElement.querySelector(`.${CSS_CLASS_DROPDOWNLISTITEM}`); + + UIInteractions.simulateClickEvent(firstItem); + fixture.detectChanges(); + + const firstRegionCellObject = grid.getCellByColumn(0, 'Region'); + expect(firstRegionCellObject.value).toEqual(fixture.componentInstance.regions[0]); + + try { + // combo should not throw from the selection getter at this point + grid.navigateTo(fixture.componentInstance.data.length - 1, 0); + await wait(30); + fixture.detectChanges(); + } catch (error) { + fail(`Test failed with error: ${error}`) + } + + const virtState = grid.verticalScrollContainer.state; + expect(virtState.startIndex).toBe(grid.dataView.length - virtState.chunkSize); + + // These will fail in case the editor (combo) in the cell display template is not bound to the cell value + // as the first record's selected value will be applied on the reused combos bc of the virtualization + for (let i = virtState.startIndex; i < virtState.startIndex + virtState.chunkSize && i < grid.dataView.length; i++) { + const targetCell = grid.gridAPI.get_cell_by_index(i, 'Region') as any; + comboNativeEl = targetCell.nativeElement.querySelector(SIMPLE_COMBO_ELEMENT); + const comboInput = comboNativeEl.querySelector('input'); + expect(comboInput.value).toBe('', `Failed on index: ${i.toString()}`); + } + + for (let i = virtState.startIndex; i < virtState.startIndex + virtState.chunkSize && i < grid.dataView.length; i++) { + const cell = grid.getCellByColumn(i, 'Region'); + expect(cell.value).toBe(undefined); + } + }); + }); }); +@Component({ + template: ` + + + + + +
+ + +
+
+
+
+ `, + standalone: true, + imports: [IgxSimpleComboComponent, IGX_GRID_DIRECTIVES, FormsModule] +}) +class IgxSimpleComboInGridComponent { + @ViewChild('grid', { read: IgxGridComponent, static: true }) + public grid: IgxGridComponent; + + public data = []; + public regions = []; + constructor() { + for (let i = 1; i <= 15; i++) { + this.data.push({ + ID: i, + region: undefined + }); + } + for (let i = 1; i <= 5; i++) { + this.regions.push(`Region ${i}`); + } + } +} + @Component({ template: ` Date: Wed, 19 Jun 2024 13:04:49 +0300 Subject: [PATCH 2/4] fix(combo): restore selection when id is changed --- .../src/lib/combo/combo.common.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/combo/combo.common.ts b/projects/igniteui-angular/src/lib/combo/combo.common.ts index 7d108f77de8..158e9caf7ce 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.common.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.common.ts @@ -167,7 +167,20 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh */ @HostBinding('attr.id') @Input() - public id = `igx-combo-${NEXT_ID++}`; + public get id(): string { + return this._id; + } + + public set id(value: string) { + if (!value) { + return; + } + const selection = this.selectionService.get(this._id); + this._id = value; + if (selection) { + this.selectionService.set(this._id, selection); + } + } /** * Sets the style width of the element @@ -943,6 +956,7 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh protected compareCollator = new Intl.Collator(); protected computedStyles; + private _id: string = `igx-combo-${NEXT_ID++}`; private _type = null; private _dataType = ''; private _itemHeight = null; From 27eb1a56f142fff54b8306e8b243980cbaef6800 Mon Sep 17 00:00:00 2001 From: ddaribo Date: Tue, 25 Jun 2024 13:36:25 +0300 Subject: [PATCH 3/4] fix(combo): close dropdown in case of changing id --- projects/igniteui-angular/src/lib/combo/combo.common.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/igniteui-angular/src/lib/combo/combo.common.ts b/projects/igniteui-angular/src/lib/combo/combo.common.ts index 158e9caf7ce..b33b6ff0e1a 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.common.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.common.ts @@ -180,6 +180,9 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh if (selection) { this.selectionService.set(this._id, selection); } + if (this.dropdown.open) { + this.dropdown.close(); + } } /** From bb5d22a55de7fd7b2c91e8a919a76f1338a1efa8 Mon Sep 17 00:00:00 2001 From: ddaribo Date: Thu, 27 Jun 2024 10:45:33 +0300 Subject: [PATCH 4/4] fix(combo): handle input focus when id is changed --- projects/igniteui-angular/src/lib/combo/combo.common.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/igniteui-angular/src/lib/combo/combo.common.ts b/projects/igniteui-angular/src/lib/combo/combo.common.ts index b33b6ff0e1a..5009d00be12 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.common.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.common.ts @@ -183,6 +183,10 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh if (this.dropdown.open) { this.dropdown.close(); } + if (this.inputGroup?.isFocused) { + this.inputGroup.element.nativeElement.blur(); + this.inputGroup.isFocused = false; + } } /**