diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.spec.ts index 314d4947da..3cba2a3446 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.spec.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.spec.ts @@ -1,4 +1,9 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { + ComponentFixture, + TestBed, + fakeAsync, + tick, +} from '@angular/core/testing'; import { expect, expectAsync } from '@skyux-sdk/testing'; import { @@ -85,8 +90,9 @@ describe('SkyCellEditorAutocompleteComponent', () => { expect(component.editorForm.get('selection')?.value).toEqual(selection); }); - it('should respond to focus changes', () => { + it('should respond to focus changes', fakeAsync(() => { component.agInit(cellEditorParams as SkyCellEditorAutocompleteParams); + tick(); component.onAutocompleteOpenChange(true); component.onBlur(); @@ -95,7 +101,7 @@ describe('SkyCellEditorAutocompleteComponent', () => { component.onAutocompleteOpenChange(false); component.onBlur(); expect(cellEditorParams.api?.stopEditing).toHaveBeenCalled(); - }); + })); it('should set the correct aria label', () => { api.getDisplayNameForColumn.and.returnValue('Testing'); @@ -282,20 +288,21 @@ describe('SkyCellEditorAutocompleteComponent', () => { }; }); - it('should focus on the input after it attaches to the DOM', () => { + it('should focus on the input after it attaches to the DOM', fakeAsync(() => { fixture.detectChanges(); const input = nativeElement.querySelector('input') as HTMLInputElement; spyOn(input, 'focus'); component.afterGuiAttached(); + tick(); expect(input).toBeVisible(); expect(input.focus).toHaveBeenCalled(); - }); + })); describe('cellStartedEdit is true', () => { - it('does not select the input value if Backspace triggers the edit', () => { + it('does not select the input value if Backspace triggers the edit', fakeAsync(() => { component.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.BACKSPACE, @@ -305,12 +312,13 @@ describe('SkyCellEditorAutocompleteComponent', () => { const selectSpy = spyOn(input, 'select'); component.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if Delete triggers the edit', () => { + it('does not select the input value if Delete triggers the edit', fakeAsync(() => { component.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.DELETE, @@ -320,12 +328,13 @@ describe('SkyCellEditorAutocompleteComponent', () => { const selectSpy = spyOn(input, 'select'); component.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if F2 triggers the edit', () => { + it('does not select the input value if F2 triggers the edit', fakeAsync(() => { component.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.F2, @@ -335,12 +344,13 @@ describe('SkyCellEditorAutocompleteComponent', () => { const selectSpy = spyOn(input, 'select'); component.afterGuiAttached(); + tick(); expect(input.value).toBe(selection.name); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('selects the input value if Enter triggers the edit', () => { + it('selects the input value if Enter triggers the edit', fakeAsync(() => { component.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.ENTER, @@ -350,12 +360,13 @@ describe('SkyCellEditorAutocompleteComponent', () => { const selectSpy = spyOn(input, 'select'); component.afterGuiAttached(); + tick(); expect(input.value).toBe(selection.name); expect(selectSpy).toHaveBeenCalledTimes(1); - }); + })); - it('does not select the input value when a standard keyboard event triggers the edit', () => { + it('does not select the input value when a standard keyboard event triggers the edit', fakeAsync(() => { component.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: 'a', @@ -365,11 +376,12 @@ describe('SkyCellEditorAutocompleteComponent', () => { const selectSpy = spyOn(input, 'select').and.callThrough(); component.afterGuiAttached(); + tick(); fixture.detectChanges(); expect(input.value).toBe('a'); expect(selectSpy).toHaveBeenCalledTimes(1); - }); + })); }); describe('cellStartedEdit is false', () => { diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.ts index dff23da90b..0564d7ada3 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-autocomplete/cell-editor-autocomplete.component.ts @@ -75,24 +75,29 @@ export class SkyAgGridCellEditorAutocompleteComponent } public afterGuiAttached(): void { - if (this.input) { - this.input.nativeElement.focus(); - if (this.#triggerType === SkyAgGridCellEditorInitialAction.Replace) { - const charPress = this.#params?.eventKey as string; + // AG Grid sets focus to the cell via setTimeout, and this queues the input to focus after that. + setTimeout(() => { + if (this.input) { + this.input.nativeElement.focus(); + if (this.#triggerType === SkyAgGridCellEditorInitialAction.Replace) { + const charPress = this.#params?.eventKey as string; - this.input.nativeElement.select(); - this.input.nativeElement.setRangeText(charPress); - // Ensure the cursor is at the end of the text. - this.input.nativeElement.setSelectionRange( - charPress.length, - charPress.length, - ); - this.input.nativeElement.dispatchEvent(new Event('input')); + this.input.nativeElement.select(); + this.input.nativeElement.setRangeText(charPress); + // Ensure the cursor is at the end of the text. + this.input.nativeElement.setSelectionRange( + charPress.length, + charPress.length, + ); + this.input.nativeElement.dispatchEvent(new Event('input')); + } + if ( + this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted + ) { + this.input.nativeElement.select(); + } } - if (this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted) { - this.input.nativeElement.select(); - } - } + }); } public getValue(): any | undefined { diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.spec.ts index 02815d5ebc..0c6ca7f41c 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.spec.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.spec.ts @@ -91,7 +91,7 @@ describe('SkyCellEditorCurrencyComponent', () => { }; }); - it('initializes the SkyAgGridCellEditorCurrencyComponent properties', () => { + it('initializes the SkyAgGridCellEditorCurrencyComponent properties', fakeAsync(() => { expect(currencyEditorComponent.columnWidth).toBeUndefined(); cellEditorParams.node = new RowNode({} as BeanCollection); @@ -113,10 +113,11 @@ describe('SkyCellEditorCurrencyComponent', () => { currencyEditorComponent.onPressEnter(); currencyEditorComponent.afterGuiAttached(); + tick(); expect(cellEditorParams.stopEditing).not.toHaveBeenCalled(); currencyEditorComponent.onPressEnter(); expect(cellEditorParams.stopEditing).toHaveBeenCalled(); - }); + })); it('should set the correct aria label', () => { api.getDisplayNameForColumn.and.returnValue('Testing'); @@ -189,7 +190,7 @@ describe('SkyCellEditorCurrencyComponent', () => { }; }); - it('sets the form control value correctly', () => { + it('sets the form control value correctly', fakeAsync(() => { expect( currencyEditorComponent.editorForm.get('currency')?.value, ).toBeNull(); @@ -197,11 +198,12 @@ describe('SkyCellEditorCurrencyComponent', () => { currencyEditorComponent.agInit(cellEditorParams as ICellEditorParams); currencyEditorFixture.detectChanges(); currencyEditorComponent.afterGuiAttached(); + tick(); expect( currencyEditorComponent.editorForm.get('currency')?.value, ).toEqual(value); - }); + })); describe('cellStartedEdit is true', () => { it('initializes with a cleared value unselected when Backspace triggers the edit', fakeAsync(() => { @@ -497,7 +499,7 @@ describe('SkyCellEditorCurrencyComponent', () => { })); }); - it('focuses on the input after it attaches to the DOM', () => { + it('focuses on the input after it attaches to the DOM', fakeAsync(() => { currencyEditorComponent.agInit(cellEditorParams as ICellEditorParams); currencyEditorFixture.detectChanges(); @@ -507,10 +509,11 @@ describe('SkyCellEditorCurrencyComponent', () => { spyOn(input, 'focus'); currencyEditorComponent.afterGuiAttached(); + tick(); expect(input).toBeVisible(); expect(input.focus).toHaveBeenCalled(); - }); + })); }); it('returns undefined if the value is not set', () => { diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.ts index ce5401f8a1..f42caa6b10 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-currency/cell-editor-currency.component.ts @@ -83,44 +83,47 @@ export class SkyAgGridCellEditorCurrencyComponent * afterGuiAttached is called by agGrid after the editor is rendered in the DOM. Once it is attached the editor is ready to be focused on. */ public afterGuiAttached(): void { - this.input?.nativeElement.focus(); - - // This setup is in `afterGuiAttached` due to the lifecycle of autonumeric which will highlight the initial value if it is in place when it renders. - // Since we don't want that, we set the initial value after autonumeric initializes. - this.#triggerType = SkyAgGridCellEditorUtils.getEditorInitialAction( - this.params, - ); - const control = this.currency; - - if (control) { - switch (this.#triggerType) { - case SkyAgGridCellEditorInitialAction.Delete: - control.setValue(undefined); - break; - case SkyAgGridCellEditorInitialAction.Replace: - control.setValue( - parseFloat(String(this.params?.eventKey)) || undefined, - ); - break; - case SkyAgGridCellEditorInitialAction.Highlighted: - case SkyAgGridCellEditorInitialAction.Untouched: - default: - control.setValue(parseFloat(String(this.params?.value))); - break; + // AG Grid sets focus to the cell via setTimeout, and this queues the input to focus after that. + setTimeout(() => { + this.input?.nativeElement.focus(); + + // This setup is in `afterGuiAttached` due to the lifecycle of autonumeric which will highlight the initial value if it is in place when it renders. + // Since we don't want that, we set the initial value after autonumeric initializes. + this.#triggerType = SkyAgGridCellEditorUtils.getEditorInitialAction( + this.params, + ); + const control = this.currency; + + if (control) { + switch (this.#triggerType) { + case SkyAgGridCellEditorInitialAction.Delete: + control.setValue(undefined); + break; + case SkyAgGridCellEditorInitialAction.Replace: + control.setValue( + parseFloat(String(this.params?.eventKey)) || undefined, + ); + break; + case SkyAgGridCellEditorInitialAction.Highlighted: + case SkyAgGridCellEditorInitialAction.Untouched: + default: + control.setValue(parseFloat(String(this.params?.value))); + break; + } } - } - this.#changeDetector.markForCheck(); + this.#changeDetector.markForCheck(); - if ( - this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted && - (this.params?.value ?? '') !== '' - ) { - this.input?.nativeElement.select(); - } + if ( + this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted && + (this.params?.value ?? '') !== '' + ) { + this.input?.nativeElement.select(); + } - // When the cell is initialized with the Enter key, we need to suppress the first `onPressEnter`. - this.#initialized = this.params?.eventKey !== 'Enter'; + // When the cell is initialized with the Enter key, we need to suppress the first `onPressEnter`. + this.#initialized = this.params?.eventKey !== 'Enter'; + }); } /** diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.spec.ts index af136803b6..a688a8540c 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.spec.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.spec.ts @@ -475,7 +475,7 @@ describe('SkyCellEditorDatepickerComponent', () => { }; }); - it('focuses on the datepicker input after it attaches to the DOM', () => { + it('focuses on the datepicker input after it attaches to the DOM', fakeAsync(() => { datepickerEditorComponent.editorForm .get('date') ?.setValue(new Date('7/12/2019')); @@ -488,13 +488,14 @@ describe('SkyCellEditorDatepickerComponent', () => { spyOn(input, 'focus'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input).toBeVisible(); expect(input.focus).toHaveBeenCalled(); - }); + })); describe('cellStartedEdit is true', () => { - it('does not select the input value if Backspace triggers the edit', () => { + it('does not select the input value if Backspace triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.BACKSPACE, @@ -506,12 +507,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if Delete triggers the edit', () => { + it('does not select the input value if Delete triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.DELETE, @@ -523,12 +525,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if F2 triggers the edit', () => { + it('does not select the input value if F2 triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.F2, @@ -540,12 +543,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('selects the input value if Enter triggers the edit', () => { + it('selects the input value if Enter triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.ENTER, @@ -557,10 +561,11 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).toHaveBeenCalledTimes(1); - }); + })); it('does not select the input value when a standard keyboard event triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ @@ -580,6 +585,7 @@ describe('SkyCellEditorDatepickerComponent', () => { ).and.callThrough(); datepickerEditorComponent.afterGuiAttached(); + tick(); datepickerEditorFixture.detectChanges(); expect(input.value).toBe('a'); @@ -598,7 +604,7 @@ describe('SkyCellEditorDatepickerComponent', () => { cellEditorParams.cellStartedEdit = false; }); - it('does not select the input value if Backspace triggers the edit', () => { + it('does not select the input value if Backspace triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.BACKSPACE, @@ -610,12 +616,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if Delete triggers the edit', () => { + it('does not select the input value if Delete triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.DELETE, @@ -627,12 +634,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if F2 triggers the edit', () => { + it('does not select the input value if F2 triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.F2, @@ -644,12 +652,13 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('selects the input value if Enter triggers the edit', () => { + it('selects the input value if Enter triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.ENTER, @@ -661,10 +670,11 @@ describe('SkyCellEditorDatepickerComponent', () => { const selectSpy = spyOn(input, 'select'); datepickerEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(dateString); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); it('does not select the input value when a standard keyboard event triggers the edit', fakeAsync(() => { datepickerEditorComponent.agInit({ @@ -684,6 +694,7 @@ describe('SkyCellEditorDatepickerComponent', () => { ).and.callThrough(); datepickerEditorComponent.afterGuiAttached(); + tick(); datepickerEditorFixture.detectChanges(); expect(input.value).toBe(dateString); diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.ts index 743f55ffa4..7609132728 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-datepicker/cell-editor-datepicker.component.ts @@ -142,39 +142,44 @@ export class SkyAgGridCellEditorDatepickerComponent * afterGuiAttached is called by agGrid after the editor is rendered in the DOM. Once it is attached the editor is ready to be focused on. */ public afterGuiAttached(): void { - const datepickerInputEl = this.datepickerInput?.nativeElement as - | HTMLInputElement - | undefined; - - if (datepickerInputEl) { - datepickerInputEl.focus(); - - // programmatically set the value of in the input; however, do not do this via the form control so that the value is not formatted when editing starts. - // Watch for the first blur and fire a 'change' event as programmatic changes won't queue a change event, but we need to do this so that formatting happens if the user tabs to the calendar button. - if (this.#triggerType === SkyAgGridCellEditorInitialAction.Replace) { - fromEvent(datepickerInputEl, 'blur') - .pipe(first()) - .subscribe(() => { - datepickerInputEl.dispatchEvent(new Event('change')); - }); - datepickerInputEl.select(); - - const charPress = this.#params?.eventKey as string; - - if (charPress) { - datepickerInputEl.setRangeText(charPress); - // Ensure the cursor is at the end of the text. - datepickerInputEl.setSelectionRange( - charPress.length, - charPress.length, - ); + // AG Grid sets focus to the cell via setTimeout, and this queues the input to focus after that. + setTimeout(() => { + const datepickerInputEl = this.datepickerInput?.nativeElement as + | HTMLInputElement + | undefined; + + if (datepickerInputEl) { + datepickerInputEl.focus(); + + // programmatically set the value of in the input; however, do not do this via the form control so that the value is not formatted when editing starts. + // Watch for the first blur and fire a 'change' event as programmatic changes won't queue a change event, but we need to do this so that formatting happens if the user tabs to the calendar button. + if (this.#triggerType === SkyAgGridCellEditorInitialAction.Replace) { + fromEvent(datepickerInputEl, 'blur') + .pipe(first()) + .subscribe(() => { + datepickerInputEl.dispatchEvent(new Event('change')); + }); + datepickerInputEl.select(); + + const charPress = this.#params?.eventKey as string; + + if (charPress) { + datepickerInputEl.setRangeText(charPress); + // Ensure the cursor is at the end of the text. + datepickerInputEl.setSelectionRange( + charPress.length, + charPress.length, + ); + } } - } - if (this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted) { - datepickerInputEl.select(); + if ( + this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted + ) { + datepickerInputEl.select(); + } } - } + }); } /** diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.spec.ts index 37089c4194..7256b2f62c 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.spec.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.spec.ts @@ -1,4 +1,9 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { + ComponentFixture, + TestBed, + fakeAsync, + tick, +} from '@angular/core/testing'; import { expect, expectAsync } from '@skyux-sdk/testing'; import { @@ -291,7 +296,7 @@ describe('SkyCellEditorTextComponent', () => { }; }); - it('focuses on the input after it attaches to the DOM', () => { + it('focuses on the input after it attaches to the DOM', fakeAsync(() => { textEditorFixture.detectChanges(); const input = textEditorNativeElement.querySelector( @@ -300,13 +305,14 @@ describe('SkyCellEditorTextComponent', () => { spyOn(input, 'focus'); textEditorComponent.afterGuiAttached(); + tick(); expect(input).toBeVisible(); expect(input.focus).toHaveBeenCalled(); - }); + })); describe('cellStartedEdit is true', () => { - it('does not select the input value if Backspace triggers the edit', () => { + it('does not select the input value if Backspace triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.BACKSPACE, @@ -318,12 +324,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if Delete triggers the edit', () => { + it('does not select the input value if Delete triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.DELETE, @@ -335,12 +342,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(''); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if F2 triggers the edit', () => { + it('does not select the input value if F2 triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.F2, @@ -352,12 +360,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('selects the input value if Enter triggers the edit', () => { + it('selects the input value if Enter triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.ENTER, @@ -369,12 +378,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).toHaveBeenCalled(); - }); + })); - it('does not select the input value when a standard keyboard event triggers the edit', () => { + it('does not select the input value when a standard keyboard event triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: 'a', @@ -386,10 +396,11 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe('a'); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); }); describe('cellStartedEdit is false', () => { @@ -397,7 +408,7 @@ describe('SkyCellEditorTextComponent', () => { cellEditorParams.cellStartedEdit = false; }); - it('does not select the input value if Backspace triggers the edit', () => { + it('does not select the input value if Backspace triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.BACKSPACE, @@ -409,12 +420,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if Delete triggers the edit', () => { + it('does not select the input value if Delete triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.DELETE, @@ -426,12 +438,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value if F2 triggers the edit', () => { + it('does not select the input value if F2 triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.F2, @@ -443,12 +456,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('should not select the input value if Enter triggers the edit', () => { + it('should not select the input value if Enter triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: KeyCode.ENTER, @@ -460,12 +474,13 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); - it('does not select the input value when a standard keyboard event triggers the edit', () => { + it('does not select the input value when a standard keyboard event triggers the edit', fakeAsync(() => { textEditorComponent.agInit({ ...(cellEditorParams as ICellEditorParams), eventKey: 'a', @@ -477,10 +492,11 @@ describe('SkyCellEditorTextComponent', () => { const selectSpy = spyOn(input, 'select'); textEditorComponent.afterGuiAttached(); + tick(); expect(input.value).toBe(value); expect(selectSpy).not.toHaveBeenCalled(); - }); + })); }); }); diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.ts index 67b0a0a8e5..d9312a1b44 100644 --- a/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.ts +++ b/libs/components/ag-grid/src/lib/modules/ag-grid/cell-editors/cell-editor-text/cell-editor-text.component.ts @@ -82,12 +82,17 @@ export class SkyAgGridCellEditorTextComponent * afterGuiAttached is called by agGrid after the editor is rendered in the DOM. Once it is attached the editor is ready to be focused on. */ public afterGuiAttached(): void { - if (this.input) { - this.input.nativeElement.focus(); - if (this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted) { - this.input.nativeElement.select(); + // AG Grid sets focus to the cell via setTimeout, and this queues the input to focus after that. + setTimeout(() => { + if (this.input) { + this.input.nativeElement.focus(); + if ( + this.#triggerType === SkyAgGridCellEditorInitialAction.Highlighted + ) { + this.input.nativeElement.select(); + } } - } + }); } /**