Skip to content

Commit 206ebc4

Browse files
crisbetojelbourn
authored andcommitted
fix(selection-list): allow jumping to first/last item using home/end (#9062)
Allows users to jump focus to the first and last items in a selection list using the home and end keys.
1 parent 38481c6 commit 206ebc4

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import {DOWN_ARROW, SPACE, ENTER, UP_ARROW} from '@angular/cdk/keycodes';
1+
import {DOWN_ARROW, END, ENTER, HOME, SPACE, 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, dispatchKeyboardEvent} from '@angular/cdk/testing';
44
import {Component, DebugElement} from '@angular/core';
55
import {async, ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
6+
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
67
import {By} from '@angular/platform-browser';
78
import {
89
MatListModule,
910
MatListOption,
1011
MatListOptionChange,
1112
MatSelectionList,
12-
MatSelectionListChange
13+
MatSelectionListChange,
1314
} from './index';
14-
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
1515

1616
describe('MatSelectionList without forms', () => {
1717
describe('with list option', () => {
@@ -264,6 +264,29 @@ describe('MatSelectionList without forms', () => {
264264
expect(manager.activeItemIndex).toEqual(3);
265265
});
266266

267+
it('should focus the first non-disabled item when pressing HOME', () => {
268+
const manager = selectionList.componentInstance._keyManager;
269+
expect(manager.activeItemIndex).toBe(-1);
270+
271+
const event = dispatchKeyboardEvent(selectionList.nativeElement, 'keydown', HOME);
272+
fixture.detectChanges();
273+
274+
// Note that the first item is disabled so we expect the second one to be focused.
275+
expect(manager.activeItemIndex).toBe(1);
276+
expect(event.defaultPrevented).toBe(true);
277+
});
278+
279+
it('should focus the last item when pressing END', () => {
280+
const manager = selectionList.componentInstance._keyManager;
281+
expect(manager.activeItemIndex).toBe(-1);
282+
283+
const event = dispatchKeyboardEvent(selectionList.nativeElement, 'keydown', END);
284+
fixture.detectChanges();
285+
286+
expect(manager.activeItemIndex).toBe(3);
287+
expect(event.defaultPrevented).toBe(true);
288+
});
289+
267290
it('should be able to select all options', () => {
268291
const list: MatSelectionList = selectionList.componentInstance;
269292

src/lib/list/selection-list.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y';
1010
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1111
import {SelectionModel} from '@angular/cdk/collections';
12-
import {SPACE, ENTER} from '@angular/cdk/keycodes';
12+
import {END, ENTER, HOME, SPACE} from '@angular/cdk/keycodes';
1313
import {
1414
AfterContentInit,
1515
Attribute,
@@ -29,6 +29,7 @@ import {
2929
QueryList,
3030
ViewEncapsulation,
3131
} from '@angular/core';
32+
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
3233
import {
3334
CanDisable,
3435
CanDisableRipple,
@@ -39,7 +40,6 @@ import {
3940
mixinDisableRipple,
4041
mixinTabIndex,
4142
} from '@angular/material/core';
42-
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
4343

4444

4545
/** @docs-private */
@@ -356,6 +356,12 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
356356
// Always prevent space from scrolling the page since the list has focus
357357
event.preventDefault();
358358
break;
359+
case HOME:
360+
case END:
361+
event.keyCode === HOME ? this._keyManager.setFirstItemActive() :
362+
this._keyManager.setLastItemActive();
363+
event.preventDefault();
364+
break;
359365
default:
360366
this._keyManager.onKeydown(event);
361367
}

0 commit comments

Comments
 (0)