Skip to content

Commit e6d9494

Browse files
crisbetoandrewseguin
authored andcommitted
fix(selection-list): support selecting all via ctrl + a (#11502)
Based on the a11y guidelines, listboxes can be able to select/deselect all using ctrl + a. These changes implement the keyboard shortcut on the selection list.
1 parent 0675e05 commit e6d9494

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

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

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {DOWN_ARROW, SPACE, ENTER, UP_ARROW, HOME, END} from '@angular/cdk/keycodes';
1+
import {DOWN_ARROW, SPACE, ENTER, UP_ARROW, HOME, END, A} from '@angular/cdk/keycodes';
22
import {
33
createKeyboardEvent,
44
dispatchFakeEvent,
@@ -321,6 +321,48 @@ describe('MatSelectionList without forms', () => {
321321
expect(event.defaultPrevented).toBe(true);
322322
});
323323

324+
it('should select all items using ctrl + a', () => {
325+
const event = createKeyboardEvent('keydown', A, selectionList.nativeElement);
326+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
327+
328+
expect(listOptions.some(option => option.componentInstance.selected)).toBe(false);
329+
330+
dispatchEvent(selectionList.nativeElement, event);
331+
fixture.detectChanges();
332+
333+
expect(listOptions.every(option => option.componentInstance.selected)).toBe(true);
334+
});
335+
336+
it('should select all items using ctrl + a if some items are selected', () => {
337+
const event = createKeyboardEvent('keydown', A, selectionList.nativeElement);
338+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
339+
340+
listOptions.slice(0, 2).forEach(option => option.componentInstance.selected = true);
341+
fixture.detectChanges();
342+
343+
expect(listOptions.some(option => option.componentInstance.selected)).toBe(true);
344+
345+
dispatchEvent(selectionList.nativeElement, event);
346+
fixture.detectChanges();
347+
348+
expect(listOptions.every(option => option.componentInstance.selected)).toBe(true);
349+
});
350+
351+
it('should deselect all with ctrl + a if all options are selected', () => {
352+
const event = createKeyboardEvent('keydown', A, selectionList.nativeElement);
353+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
354+
355+
listOptions.forEach(option => option.componentInstance.selected = true);
356+
fixture.detectChanges();
357+
358+
expect(listOptions.every(option => option.componentInstance.selected)).toBe(true);
359+
360+
dispatchEvent(selectionList.nativeElement, event);
361+
fixture.detectChanges();
362+
363+
expect(listOptions.every(option => option.componentInstance.selected)).toBe(false);
364+
});
365+
324366
it('should be able to jump focus down to an item by typing', fakeAsync(() => {
325367
const listEl = selectionList.nativeElement;
326368
const manager = selectionList.componentInstance._keyManager;

src/lib/list/selection-list.ts

Lines changed: 7 additions & 1 deletion
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, HOME, END, UP_ARROW, DOWN_ARROW} from '@angular/cdk/keycodes';
12+
import {SPACE, ENTER, HOME, END, UP_ARROW, DOWN_ARROW, A} from '@angular/cdk/keycodes';
1313
import {
1414
AfterContentInit,
1515
Attribute,
@@ -394,6 +394,12 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
394394
keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
395395
event.preventDefault();
396396
break;
397+
case A:
398+
if (event.ctrlKey) {
399+
this.options.find(option => !option.selected) ? this.selectAll() : this.deselectAll();
400+
event.preventDefault();
401+
}
402+
break;
397403
default:
398404
manager.onKeydown(event);
399405
}

0 commit comments

Comments
 (0)