From 93f3f684605b98380ba077acc502b66ee25602a5 Mon Sep 17 00:00:00 2001 From: Georgi Anastasov Date: Thu, 29 Aug 2024 11:16:04 +0300 Subject: [PATCH 1/2] feat(simple-combo): allow values to be selected on tab press --- CHANGELOG.md | 4 +++ .../simple-combo.component.spec.ts | 36 +++++++++++++------ .../simple-combo/simple-combo.component.ts | 11 ++++-- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5797f1296d8..22a5dd7831a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes for each version of this project will be documented in this file. ## 18.2.0 +### New Features +- `IgxSimpleCombo` + - Introduced ability for Simple Combo to automatically select and retain valid input on "Tab" press enhancing user experience by streamlining data entry and reducing the need for manual selection improving form navigation. + ### General - `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`, `IgxPivotGrid` - **Breaking Change** The `shouldGenerate` property have been deprecated and will be removed in a future version. Use `autoGenerate` instead. Automatic migration to this is available and will be applied on `ng update`. 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 c3e69feecdf..b817bf85dae 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 @@ -1241,20 +1241,36 @@ describe('IgxSimpleCombo', () => { expect(combo.close).toHaveBeenCalledTimes(1); }); - it('should clear the input on blur with a partial match', () => { - spyOn(combo as any, 'clearSelection').and.callThrough(); + it('should select first match item on tab key pressed', () => { + input.triggerEventHandler('focus', {}); + fixture.detectChanges(); + + const toggleButton = fixture.debugElement.query(By.css('.' + CSS_CLASS_TOGGLEBUTTON)); + toggleButton.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + + UIInteractions.simulateTyping('connecticut', input); + fixture.detectChanges(); + + UIInteractions.triggerEventHandlerKeyDown('Tab', input); + fixture.detectChanges(); + + expect(combo.displayValue).toEqual('Connecticut'); + expect(combo.comboInput.value).toEqual('Connecticut'); + }); + + it('should not clear the input on blur with a partial match but it should select the match item', () => { spyOn(combo.dropdown.closing, 'emit').and.callThrough(); input.triggerEventHandler('focus', {}); fixture.detectChanges(); - UIInteractions.simulateTyping('new', input); + UIInteractions.simulateTyping('mic', input); UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect((combo as any).clearSelection).toHaveBeenCalledOnceWith(true); + expect(combo.displayValue).toEqual('Michigan'); expect(combo.dropdown.closing.emit).toHaveBeenCalledTimes(1); - expect(combo.displayValue).toEqual(''); }); it('should not clear the selection and input on blur with a match', () => { @@ -1281,7 +1297,7 @@ describe('IgxSimpleCombo', () => { expect(combo.selection).toBeDefined() }); - it('should clear input on blur when dropdown is collapsed with no match', () => { + it('should not clear input on blur when dropdown is collapsed with match', () => { input.triggerEventHandler('focus', {}); fixture.detectChanges(); @@ -1294,8 +1310,8 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.displayValue).toEqual(''); - expect(combo.selection).not.toBeDefined() + expect(combo.displayValue).toEqual('New Jersey'); + expect(combo.selection).toBeDefined() }); it('should open the combo when input is focused', () => { @@ -2551,7 +2567,7 @@ describe('IgxSimpleCombo', () => { const selectedItem = combo.data[combo.data.length - 1]; expect(combo.displayValue).toEqual(`${selectedItem[combo.displayKey]}`); })); - it('should clear input on blur when bound to remote data and no item is selected', () => { + it('should not clear input on blur when bound to remote data and item is selected', () => { input.triggerEventHandler('focus', {}); fixture.detectChanges(); @@ -2561,7 +2577,7 @@ describe('IgxSimpleCombo', () => { UIInteractions.triggerEventHandlerKeyDown('Tab', input); fixture.detectChanges(); - expect(combo.comboInput.value).toEqual(''); + expect(combo.comboInput.value).toEqual('Product 0'); }); it('should display correct value after the value has been changed from the form and then by the user', fakeAsync(() => { 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 1c53c92091b..1efaa87d02e 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 @@ -360,8 +360,15 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co this.clearSelection(true); } if (!this.collapsed && event.key === this.platformUtil.KEYMAP.TAB) { - this.clearOnBlur(); - this.close(); + const focusedItem = this.dropdown.focusedItem; + if (focusedItem && !focusedItem.isHeader) { + this.select(focusedItem.itemID); + this.close(); + this.textSelection.trigger(); + } else { + this.clearOnBlur(); + this.close(); + } } this.composing = false; super.handleKeyDown(event); From 21691cbb957455c23364c4d8e2ba567e9ebb896f Mon Sep 17 00:00:00 2001 From: Georgi Anastasov Date: Mon, 9 Sep 2024 16:23:33 +0300 Subject: [PATCH 2/2] feat(simple-combo): prevent non-existent item selection on Tab key --- .../simple-combo.component.spec.ts | 18 ++++++++++++++++++ .../lib/simple-combo/simple-combo.component.ts | 6 ++++++ 2 files changed, 24 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 c714d11889b..36b15ac753e 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 @@ -1442,6 +1442,24 @@ describe('IgxSimpleCombo', () => { expect(combo.comboInput.value).toEqual('Connecticut'); }); + it('should not select any item if input does not match data on tab key pressed', () => { + input.triggerEventHandler('focus', {}); + fixture.detectChanges(); + + const toggleButton = fixture.debugElement.query(By.css('.' + CSS_CLASS_TOGGLEBUTTON)); + toggleButton.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + + UIInteractions.simulateTyping('nonexistent', input); + fixture.detectChanges(); + + UIInteractions.triggerEventHandlerKeyDown('Tab', input); + fixture.detectChanges(); + + expect(combo.displayValue).toEqual(''); + expect(combo.comboInput.value).toEqual(''); + }); + it('should not clear the input on blur with a partial match but it should select the match item', () => { spyOn(combo.dropdown.closing, 'emit').and.callThrough(); 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 1e8c5cad789..f2cf11e6e02 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 @@ -361,6 +361,12 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co this.clearSelection(true); } if (!this.collapsed && event.key === this.platformUtil.KEYMAP.TAB) { + const filtered = this.filteredData.find(this.findAllMatches); + if (filtered === null || filtered === undefined) { + this.clearOnBlur(); + this.close(); + return; + } const focusedItem = this.dropdown.focusedItem; if (focusedItem && !focusedItem.isHeader) { this.select(focusedItem.itemID);