diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index cc9022b03bab..2a68ced25c9c 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -71,8 +71,8 @@ import { } from './select-errors'; -/** The debounce interval when typing letters to select an option. */ -const LETTER_KEY_DEBOUNCE_INTERVAL = 200; +/** Default debounce interval when typing letters to select an option. */ +const DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL = 200; describe('MatSelect', () => { let overlayContainer: OverlayContainer; @@ -469,20 +469,42 @@ describe('MatSelect', () => { expect(formControl.value).toBeFalsy('Expected no initial value.'); dispatchEvent(select, createKeyboardEvent('keydown', 80, undefined, 'p')); - tick(200); + tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL); expect(options[1].selected).toBe(true, 'Expected second option to be selected.'); expect(formControl.value).toBe(options[1].value, 'Expected value from second option to have been set on the model.'); dispatchEvent(select, createKeyboardEvent('keydown', 69, undefined, 'e')); - tick(200); + tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL); expect(options[5].selected).toBe(true, 'Expected sixth option to be selected.'); expect(formControl.value).toBe(options[5].value, 'Expected value from sixth option to have been set on the model.'); })); + it('should be able to customize the typeahead debounce interval', fakeAsync(() => { + const formControl = fixture.componentInstance.control; + const options = fixture.componentInstance.options.toArray(); + + fixture.componentInstance.typeaheadDebounceInterval = 1337; + fixture.detectChanges(); + + expect(formControl.value).toBeFalsy('Expected no initial value.'); + + dispatchEvent(select, createKeyboardEvent('keydown', 80, undefined, 'p')); + tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL); + + expect(formControl.value).toBeFalsy('Expected no value after a bit of time has passed.'); + + tick(1337); + + expect(options[1].selected) + .toBe(true, 'Expected second option to be selected after all the time has passed.'); + expect(formControl.value).toBe(options[1].value, + 'Expected value from second option to have been set on the model.'); + })); + it('should open the panel when pressing a vertical arrow key on a closed multiple select', fakeAsync(() => { fixture.destroy(); @@ -1969,7 +1991,7 @@ describe('MatSelect', () => { // Press the letter 'o' 15 times since all the options are named 'Option ' dispatchEvent(host, createKeyboardEvent('keydown', 79, undefined, 'o')); fixture.detectChanges(); - tick(LETTER_KEY_DEBOUNCE_INTERVAL); + tick(DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL); } flush(); @@ -4275,7 +4297,8 @@ describe('MatSelect', () => { + [panelClass]="panelClass" [disableRipple]="disableRipple" + [typeaheadDebounceInterval]="typeaheadDebounceInterval"> {{ food.viewValue }} @@ -4304,6 +4327,7 @@ class BasicSelect { ariaLabelledby: string; panelClass = ['custom-one', 'custom-two']; disableRipple: boolean; + typeaheadDebounceInterval: number; @ViewChild(MatSelect, {static: true}) select: MatSelect; @ViewChildren(MatOption) options: QueryList; diff --git a/src/material/select/select.ts b/src/material/select/select.ts index f8875435c053..7b6df93f2a36 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -426,6 +426,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, /** Object used to control when error messages are shown. */ @Input() errorStateMatcher: ErrorStateMatcher; + /** Time to wait in milliseconds after the last keystroke before moving focus to an item. */ + @Input() typeaheadDebounceInterval: number; + /** * Function used to sort the values in a select in multiple mode. * Follows the same logic as `Array.prototype.sort`. @@ -570,6 +573,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, if (changes['disabled']) { this.stateChanges.next(); } + + if (changes['typeaheadDebounceInterval'] && this._keyManager) { + this._keyManager.withTypeAhead(this.typeaheadDebounceInterval); + } } ngOnDestroy() { @@ -897,7 +904,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, /** Sets up a key manager to listen to keyboard events on the overlay panel. */ private _initKeyManager() { this._keyManager = new ActiveDescendantKeyManager(this.options) - .withTypeAhead() + .withTypeAhead(this.typeaheadDebounceInterval) .withVerticalOrientation() .withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr') .withAllowedModifierKeys(['shiftKey']); diff --git a/tools/public_api_guard/material/select.d.ts b/tools/public_api_guard/material/select.d.ts index dd2ae29bc6dd..ec4d55233bbd 100644 --- a/tools/public_api_guard/material/select.d.ts +++ b/tools/public_api_guard/material/select.d.ts @@ -61,6 +61,7 @@ export declare class MatSelect extends _MatSelectMixinBase implements AfterConte sortComparator: (a: MatOption, b: MatOption, options: MatOption[]) => number; trigger: ElementRef; readonly triggerValue: string; + typeaheadDebounceInterval: number; value: any; readonly valueChange: EventEmitter; constructor(_viewportRuler: ViewportRuler, _changeDetectorRef: ChangeDetectorRef, _ngZone: NgZone, _defaultErrorStateMatcher: ErrorStateMatcher, elementRef: ElementRef, _dir: Directionality, _parentForm: NgForm, _parentFormGroup: FormGroupDirective, _parentFormField: MatFormField, ngControl: NgControl, tabIndex: string, scrollStrategyFactory: any,