Skip to content

Commit 111330f

Browse files
Merge pull request #14414 from IgniteUI/bpachilova/comboIdChangeInTemplate-fix-14305-master
fix(combo): Handle selection when placed in an IgxGrid cell template and grid is virtualized - master
2 parents 6d3a534 + dc56352 commit 111330f

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

projects/igniteui-angular/src/lib/combo/combo.common.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,27 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
167167
*/
168168
@HostBinding('attr.id')
169169
@Input()
170-
public id = `igx-combo-${NEXT_ID++}`;
170+
public get id(): string {
171+
return this._id;
172+
}
173+
174+
public set id(value: string) {
175+
if (!value) {
176+
return;
177+
}
178+
const selection = this.selectionService.get(this._id);
179+
this._id = value;
180+
if (selection) {
181+
this.selectionService.set(this._id, selection);
182+
}
183+
if (this.dropdown.open) {
184+
this.dropdown.close();
185+
}
186+
if (this.inputGroup?.isFocused) {
187+
this.inputGroup.element.nativeElement.blur();
188+
this.inputGroup.isFocused = false;
189+
}
190+
}
171191

172192
/**
173193
* Sets the style width of the element
@@ -943,6 +963,7 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
943963
protected compareCollator = new Intl.Collator();
944964
protected computedStyles;
945965

966+
private _id: string = `igx-combo-${NEXT_ID++}`;
946967
private _type = null;
947968
private _dataType = '';
948969
private _itemHeight = null;

projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.spec.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { AbsoluteScrollStrategy, AutoPositionStrategy, ConnectedPositioningStrat
1616
import { configureTestSuite } from '../test-utils/configure-suite';
1717
import { UIInteractions, wait } from '../test-utils/ui-interactions.spec';
1818
import { IgxSimpleComboComponent, ISimpleComboSelectionChangingEventArgs } from './public_api';
19+
import { IgxGridComponent } from '../grids/grid/grid.component';
20+
import { IGX_GRID_DIRECTIVES } from '../grids/grid/public_api';
1921

2022

2123
const CSS_CLASS_COMBO = 'igx-combo';
@@ -2563,8 +2565,109 @@ describe('IgxSimpleCombo', () => {
25632565
expect(input.nativeElement.value).toEqual('Product 5');
25642566
}));
25652567
});
2568+
2569+
describe('Integration', () => {
2570+
let grid: IgxGridComponent;
2571+
2572+
beforeAll(waitForAsync(() => {
2573+
TestBed.configureTestingModule({
2574+
imports: [
2575+
NoopAnimationsModule,
2576+
IgxSimpleComboInGridComponent
2577+
]
2578+
}).compileComponents();
2579+
}));
2580+
beforeEach(() => {
2581+
fixture = TestBed.createComponent(IgxSimpleComboInGridComponent);
2582+
fixture.detectChanges();
2583+
grid = fixture.componentInstance.grid;
2584+
});
2585+
it('Combo in IgxGrid cell display template correctly handles selection - issue #14305', async () => {
2586+
const firstRecRegionCell = grid.gridAPI.get_cell_by_index(0, 'Region') as any;
2587+
let comboNativeEl = firstRecRegionCell.nativeElement.querySelector(SIMPLE_COMBO_ELEMENT);
2588+
const comboToggleButton = comboNativeEl.querySelector(`.${CSS_CLASS_TOGGLEBUTTON}`);
2589+
2590+
UIInteractions.simulateClickEvent(comboToggleButton);
2591+
fixture.detectChanges();
2592+
2593+
const comboDropDownList = fixture.debugElement.query(By.css(`.${CSS_CLASS_DROPDOWNLIST}`));
2594+
const firstItem = comboDropDownList.nativeElement.querySelector(`.${CSS_CLASS_DROPDOWNLISTITEM}`);
2595+
2596+
UIInteractions.simulateClickEvent(firstItem);
2597+
fixture.detectChanges();
2598+
2599+
const firstRegionCellObject = grid.getCellByColumn(0, 'Region');
2600+
expect(firstRegionCellObject.value).toEqual(fixture.componentInstance.regions[0]);
2601+
2602+
try {
2603+
// combo should not throw from the selection getter at this point
2604+
grid.navigateTo(fixture.componentInstance.data.length - 1, 0);
2605+
await wait(30);
2606+
fixture.detectChanges();
2607+
} catch (error) {
2608+
fail(`Test failed with error: ${error}`)
2609+
}
2610+
2611+
const virtState = grid.verticalScrollContainer.state;
2612+
expect(virtState.startIndex).toBe(grid.dataView.length - virtState.chunkSize);
2613+
2614+
// These will fail in case the editor (combo) in the cell display template is not bound to the cell value
2615+
// as the first record's selected value will be applied on the reused combos bc of the virtualization
2616+
for (let i = virtState.startIndex; i < virtState.startIndex + virtState.chunkSize && i < grid.dataView.length; i++) {
2617+
const targetCell = grid.gridAPI.get_cell_by_index(i, 'Region') as any;
2618+
comboNativeEl = targetCell.nativeElement.querySelector(SIMPLE_COMBO_ELEMENT);
2619+
const comboInput = comboNativeEl.querySelector('input');
2620+
expect(comboInput.value).toBe('', `Failed on index: ${i.toString()}`);
2621+
}
2622+
2623+
for (let i = virtState.startIndex; i < virtState.startIndex + virtState.chunkSize && i < grid.dataView.length; i++) {
2624+
const cell = grid.getCellByColumn(i, 'Region');
2625+
expect(cell.value).toBe(undefined);
2626+
}
2627+
});
2628+
});
25662629
});
25672630

2631+
@Component({
2632+
template: `
2633+
<igx-grid #grid [data]="data" [autoGenerate]="false" width="100%" height="500px" [primaryKey]="'ID'">
2634+
<igx-column field="ID" header="ID" [dataType]="'number'" width="100px">
2635+
</igx-column>
2636+
<igx-column field="Region" header="Region" dataType="string" width="220px">
2637+
<ng-template igxCell let-cell="cell">
2638+
<div>
2639+
<igx-simple-combo [id]="'region-' + cell.row.data.ID"
2640+
[data]="regions" placeholder="Choose Region..."
2641+
[(ngModel)]="cell.value"
2642+
>
2643+
</igx-simple-combo>
2644+
</div>
2645+
</ng-template>
2646+
</igx-column>
2647+
</igx-grid>
2648+
`,
2649+
standalone: true,
2650+
imports: [IgxSimpleComboComponent, IGX_GRID_DIRECTIVES, FormsModule]
2651+
})
2652+
class IgxSimpleComboInGridComponent {
2653+
@ViewChild('grid', { read: IgxGridComponent, static: true })
2654+
public grid: IgxGridComponent;
2655+
2656+
public data = [];
2657+
public regions = [];
2658+
constructor() {
2659+
for (let i = 1; i <= 15; i++) {
2660+
this.data.push({
2661+
ID: i,
2662+
region: undefined
2663+
});
2664+
}
2665+
for (let i = 1; i <= 5; i++) {
2666+
this.regions.push(`Region ${i}`);
2667+
}
2668+
}
2669+
}
2670+
25682671
@Component({
25692672
template: `
25702673
<igx-simple-combo #combo [placeholder]="'Location'" [data]='items' [style.--ig-size]="'var(--ig-size-' + size + ')'"

0 commit comments

Comments
 (0)