Skip to content

Commit 8fb804b

Browse files
authored
fix(material/select): don't assign typeahead value after blur (#25811)
Fixes that the select would assign the value triggered by the typeahead even if the select doesn't have focus anymore. Fixes #25452.
1 parent c0efe14 commit 8fb804b

File tree

6 files changed

+51
-0
lines changed

6 files changed

+51
-0
lines changed

src/cdk/a11y/key-manager/list-key-manager.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,17 @@ describe('Key managers', () => {
958958
keyManager.destroy();
959959
expect(keyManager.isTyping()).toBe(false);
960960
}));
961+
962+
it('should be able to cancel the typeahead sequence', fakeAsync(() => {
963+
expect(keyManager.activeItem).toBeFalsy();
964+
965+
keyManager.onKeydown(createKeyboardEvent('keydown', 79, 'o')); // types "o"
966+
expect(keyManager.activeItem).toBeFalsy();
967+
keyManager.cancelTypeahead();
968+
tick(debounceInterval);
969+
970+
expect(keyManager.activeItem).toBeFalsy();
971+
}));
961972
});
962973
});
963974

src/cdk/a11y/key-manager/list-key-manager.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
188188
return this;
189189
}
190190

191+
/** Cancels the current typeahead sequence. */
192+
cancelTypeahead(): this {
193+
this._pressedLetters = [];
194+
return this;
195+
}
196+
191197
/**
192198
* Configures the key manager to activate the first and last items
193199
* respectively when the Home or End key is pressed.

src/material/legacy-select/select.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,22 @@ describe('MatSelect', () => {
655655
.toBe(options[1].value);
656656
}));
657657

658+
it('should cancel the typeahead selection on blur', fakeAsync(() => {
659+
const formControl = fixture.componentInstance.control;
660+
const options = fixture.componentInstance.options.toArray();
661+
662+
expect(formControl.value).withContext('Expected no initial value.').toBeFalsy();
663+
664+
dispatchEvent(select, createKeyboardEvent('keydown', 80, 'p'));
665+
dispatchFakeEvent(select, 'blur');
666+
tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL);
667+
668+
expect(options.some(o => o.selected))
669+
.withContext('Expected no options to be selected.')
670+
.toBe(false);
671+
expect(formControl.value).withContext('Expected no value to be assigned.').toBeFalsy();
672+
}));
673+
658674
it('should open the panel when pressing a vertical arrow key on a closed multiple select', fakeAsync(() => {
659675
fixture.destroy();
660676

src/material/select/select.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,22 @@ describe('MDC-based MatSelect', () => {
689689
.toBe(options[1].value);
690690
}));
691691

692+
it('should cancel the typeahead selection on blur', fakeAsync(() => {
693+
const formControl = fixture.componentInstance.control;
694+
const options = fixture.componentInstance.options.toArray();
695+
696+
expect(formControl.value).withContext('Expected no initial value.').toBeFalsy();
697+
698+
dispatchEvent(select, createKeyboardEvent('keydown', 80, 'p'));
699+
dispatchFakeEvent(select, 'blur');
700+
tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL);
701+
702+
expect(options.some(o => o.selected))
703+
.withContext('Expected no options to be selected.')
704+
.toBe(false);
705+
expect(formControl.value).withContext('Expected no value to be assigned.').toBeFalsy();
706+
}));
707+
692708
it('should open the panel when pressing a vertical arrow key on a closed multiple select', fakeAsync(() => {
693709
fixture.destroy();
694710

src/material/select/select.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ export abstract class _MatSelectBase<C>
790790
*/
791791
_onBlur() {
792792
this._focused = false;
793+
this._keyManager?.cancelTypeahead();
793794

794795
if (!this.disabled && !this.panelOpen) {
795796
this._onTouched();

tools/public_api_guard/cdk/a11y.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
342342
constructor(_items: QueryList<T> | T[]);
343343
get activeItem(): T | null;
344344
get activeItemIndex(): number | null;
345+
cancelTypeahead(): this;
345346
readonly change: Subject<number>;
346347
destroy(): void;
347348
isTyping(): boolean;

0 commit comments

Comments
 (0)