Skip to content

Commit 0e58ce7

Browse files
committed
fix(selection-list): allow users to jump focus to a particular item by typing
Similarly to our other listbox-based components, this allows people to move focus to a particular item by typing the first letters of its label.
1 parent 2436acd commit 0e58ce7

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

src/lib/list/list-option.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
[matRippleTrigger]="_getHostElement()"
88
[matRippleDisabled]="_isRippleDisabled()"></div>
99

10-
<mat-pseudo-checkbox #autocheckbox
10+
<mat-pseudo-checkbox
1111
[state]="selected ? 'checked' : 'unchecked'"
1212
[disabled]="disabled"></mat-pseudo-checkbox>
1313

14-
<div class="mat-list-text"><ng-content></ng-content></div>
14+
<div class="mat-list-text" #text><ng-content></ng-content></div>
1515

1616
</div>

src/lib/list/selection-list.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {DOWN_ARROW, SPACE, ENTER, UP_ARROW} from '@angular/cdk/keycodes';
22
import {Platform} from '@angular/cdk/platform';
3-
import {createKeyboardEvent, dispatchFakeEvent} from '@angular/cdk/testing';
3+
import {createKeyboardEvent, dispatchFakeEvent, dispatchEvent} from '@angular/cdk/testing';
44
import {Component, DebugElement} from '@angular/core';
55
import {async, ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
66
import {By} from '@angular/platform-browser';
@@ -264,6 +264,25 @@ describe('MatSelectionList without forms', () => {
264264
expect(manager.activeItemIndex).toEqual(3);
265265
});
266266

267+
it('should be able to jump focus down to an item by typing', fakeAsync(() => {
268+
const listEl = selectionList.nativeElement;
269+
const manager = selectionList.componentInstance._keyManager;
270+
271+
expect(manager.activeItemIndex).toBe(-1);
272+
273+
dispatchEvent(listEl, createKeyboardEvent('keydown', 83, undefined, 's'));
274+
fixture.detectChanges();
275+
tick(200);
276+
277+
expect(manager.activeItemIndex).toBe(1);
278+
279+
dispatchEvent(listEl, createKeyboardEvent('keydown', 68, undefined, 'd'));
280+
fixture.detectChanges();
281+
tick(200);
282+
283+
expect(manager.activeItemIndex).toBe(3);
284+
}));
285+
267286
it('should be able to select all options', () => {
268287
const list: MatSelectionList = selectionList.componentInstance;
269288

src/lib/list/selection-list.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
Optional,
2828
Output,
2929
QueryList,
30+
ViewChild,
3031
ViewEncapsulation,
3132
} from '@angular/core';
3233
import {
@@ -118,6 +119,9 @@ export class MatListOption extends _MatListOptionMixinBase
118119

119120
@ContentChildren(MatLine) _lines: QueryList<MatLine>;
120121

122+
/** DOM element containing the item's text. */
123+
@ViewChild('text') _text: ElementRef;
124+
121125
/** Whether the label should appear before or after the checkbox. Defaults to 'after' */
122126
@Input() checkboxPosition: 'before' | 'after' = 'after';
123127

@@ -191,6 +195,14 @@ export class MatListOption extends _MatListOptionMixinBase
191195
this._element.nativeElement.focus();
192196
}
193197

198+
/**
199+
* Returns the list item's text label. Implemented as a part of the FocusKeyManager.
200+
* @docs-private
201+
*/
202+
getLabel() {
203+
return this._text ? this._text.nativeElement.textContent : '';
204+
}
205+
194206
/** Whether this list item should show a ripple effect when clicked. */
195207
_isRippleDisabled() {
196208
return this.disabled || this.disableRipple || this.selectionList.disableRipple;
@@ -300,7 +312,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
300312
}
301313

302314
ngAfterContentInit(): void {
303-
this._keyManager = new FocusKeyManager<MatListOption>(this.options).withWrap();
315+
this._keyManager = new FocusKeyManager<MatListOption>(this.options).withWrap().withTypeAhead();
304316
}
305317

306318
/** Focus the selection-list. */

0 commit comments

Comments
 (0)