Skip to content

Commit d5de711

Browse files
crisbetojosephperrott
authored andcommitted
fix(select): support ctrl+a shortcut for multi-select (#11799)
1 parent 8dfce58 commit d5de711

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

src/lib/select/select.spec.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
SPACE,
1010
TAB,
1111
UP_ARROW,
12+
A,
1213
} from '@angular/cdk/keycodes';
1314
import {OverlayContainer} from '@angular/cdk/overlay';
1415
import {Platform} from '@angular/cdk/platform';
@@ -3901,6 +3902,96 @@ describe('MatSelect', () => {
39013902
expect(testInstance.control.value).toEqual([null, 'pizza-1', null]);
39023903
}));
39033904

3905+
it('should select all options when pressing ctrl + a', () => {
3906+
const selectElement = fixture.nativeElement.querySelector('mat-select');
3907+
const options = fixture.componentInstance.options.toArray();
3908+
3909+
expect(testInstance.control.value).toBeFalsy();
3910+
expect(options.every(option => option.selected)).toBe(false);
3911+
3912+
fixture.componentInstance.select.open();
3913+
fixture.detectChanges();
3914+
3915+
const event = createKeyboardEvent('keydown', A, selectElement);
3916+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
3917+
dispatchEvent(selectElement, event);
3918+
fixture.detectChanges();
3919+
3920+
expect(options.every(option => option.selected)).toBe(true);
3921+
expect(testInstance.control.value).toEqual([
3922+
'steak-0',
3923+
'pizza-1',
3924+
'tacos-2',
3925+
'sandwich-3',
3926+
'chips-4',
3927+
'eggs-5',
3928+
'pasta-6',
3929+
'sushi-7'
3930+
]);
3931+
});
3932+
3933+
it('should select all options when pressing ctrl + a when some options are selected', () => {
3934+
const selectElement = fixture.nativeElement.querySelector('mat-select');
3935+
const options = fixture.componentInstance.options.toArray();
3936+
3937+
options[0].select();
3938+
fixture.detectChanges();
3939+
3940+
expect(testInstance.control.value).toEqual(['steak-0']);
3941+
expect(options.some(option => option.selected)).toBe(true);
3942+
3943+
fixture.componentInstance.select.open();
3944+
fixture.detectChanges();
3945+
3946+
const event = createKeyboardEvent('keydown', A, selectElement);
3947+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
3948+
dispatchEvent(selectElement, event);
3949+
fixture.detectChanges();
3950+
3951+
expect(options.every(option => option.selected)).toBe(true);
3952+
expect(testInstance.control.value).toEqual([
3953+
'steak-0',
3954+
'pizza-1',
3955+
'tacos-2',
3956+
'sandwich-3',
3957+
'chips-4',
3958+
'eggs-5',
3959+
'pasta-6',
3960+
'sushi-7'
3961+
]);
3962+
});
3963+
3964+
it('should deselect all options with ctrl + a if all options are selected', () => {
3965+
const selectElement = fixture.nativeElement.querySelector('mat-select');
3966+
const options = fixture.componentInstance.options.toArray();
3967+
3968+
options.forEach(option => option.select());
3969+
fixture.detectChanges();
3970+
3971+
expect(testInstance.control.value).toEqual([
3972+
'steak-0',
3973+
'pizza-1',
3974+
'tacos-2',
3975+
'sandwich-3',
3976+
'chips-4',
3977+
'eggs-5',
3978+
'pasta-6',
3979+
'sushi-7'
3980+
]);
3981+
expect(options.every(option => option.selected)).toBe(true);
3982+
3983+
fixture.componentInstance.select.open();
3984+
fixture.detectChanges();
3985+
3986+
const event = createKeyboardEvent('keydown', A, selectElement);
3987+
Object.defineProperty(event, 'ctrlKey', {get: () => true});
3988+
dispatchEvent(selectElement, event);
3989+
fixture.detectChanges();
3990+
3991+
expect(options.some(option => option.selected)).toBe(false);
3992+
expect(testInstance.control.value).toEqual([]);
3993+
});
3994+
39043995
});
39053996
});
39063997

src/lib/select/select.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
RIGHT_ARROW,
2020
SPACE,
2121
UP_ARROW,
22+
A,
2223
} from '@angular/cdk/keycodes';
2324
import {
2425
CdkConnectedOverlay,
@@ -705,6 +706,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
705706
} else if ((keyCode === ENTER || keyCode === SPACE) && manager.activeItem) {
706707
event.preventDefault();
707708
manager.activeItem._selectViaInteraction();
709+
} else if (this._multiple && keyCode === A && event.ctrlKey) {
710+
event.preventDefault();
711+
const hasDeselectedOptions = this.options.some(option => !option.selected);
712+
this.options.forEach(option => hasDeselectedOptions ? option.select() : option.deselect());
708713
} else {
709714
const previouslyFocusedIndex = manager.activeItemIndex;
710715

0 commit comments

Comments
 (0)